
/*
 * xanim.c
 *
 * Copyright (C) 1990,1991,1992,1993,1994 by Mark Podlipec. 
 * All rights reserved.
 *
 * This software may be freely copied, modified and redistributed without
 * fee for non-commerical purposes provided that this copyright notice is
 * preserved intact on all copies and modified copies.
 * 
 * There is no warranty or other guarantee of fitness of this software.
 * It is provided solely "as is". The author(s) disclaim(s) all
 * responsibility and liability with respect to this software's usage
 * or its effect upon hardware or computer systems.
 *
 */
/****************
 * Rev History
 *
 * 12Aug94 - Setup X11 error handler to detec XShmAttach failures when Disp
 *           is remote so I can backoff Shm support and continue on.
 *
 *******************************/

#define DA_REV 2.68
#define DA_MINOR_REV 5

/*
 * Any problems, suggestions, solutions, anims to show off, etc contact:
 *
 * podlipec@wellfleet.com
 *
 */

#include "Animation.h"
#include <sys/signal.h>
#ifdef MSDOS
#include <sys/resource.h>
#else /* not MSDOS */
#ifndef VMS   /* NOT MSDOS and NOT VMS ie Unix */
#include <sys/times.h>
#else   /* VMS systems */
#include <lib$routines.h>
#include <starlet.h>
#ifdef R3_INTRINSICS
typedef void *XtPointer;
#endif
#endif
#endif
#include <ctype.h>

#ifdef XSHM
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/extensions/XShm.h>
extern Visual        *theVisual;
#endif /*XSHM*/


/* POD TESTING */
ULONG fli_pad_kludge;

void TheEnd();
void TheEnd1();
void Hard_Death();
void Usage();
void Usage_Quick();
void ShowAnimation();
void ShowAction();
LONG Determine_Anim_Type();
void XA_Cycle_Wait();
void XA_Cycle_It();
void Step_File_Next();
void Step_File_Prev();
void Step_Frame_Next();
void Step_Frame_Prev();
void Step_Action_Next();
void Free_Actions();
void ACT_Free_Act();
XA_ANIM_HDR *Get_Anim_Hdr();
XA_ANIM_HDR *Return_Anim_Hdr();
void Step_Action_Prev();
LONG XA_Time_Read();
void XA_Time_Init();
void XA_Time_Check();
ULONG XA_Image_To_Pixmap();
void XA_Install_CMAP();
ULONG XA_Mapped_To_Display();
ULONG XA_Read_Int();
float XA_Read_Float();
LONG XA_Get_Class();
void XA_Read_Delta();
void XA_Add_Pause();

void X11_Setup_Window();
void X11_Map_Window();
void X11_Init_Image_Struct();
void X11_Pre_Setup();
void ACT_Make_Images();
void UTIL_Mapped_To_Mapped();
void UTIL_Mapped_To_Bitmap();
void UTIL_Mapped_To_Floyd();
UBYTE *UTIL_Scale_Mapped();
UBYTE *UTIL_Scale_Bitmap();
void UTIL_Pack_Image();

void CMAP_Manipulate_CHDRS();
void CMAP_Expand_Maps();
ULONG CMAP_Gamma_Adjust();

ULONG IFF_Read_File();
void IFF_Buffer_Action();
void IFF_Init_DLTA_HDR();
void IFF_Update_DLTA_HDR();
void IFF_Buffer_HAM6();
void IFF_Buffer_HAM8();
ULONG GIF_Read_Anim();
ULONG TXT_Read_File();
ULONG Fli_Read_File();
ULONG DL_Read_File();
ULONG PFX_Read_File();
ULONG SET_Read_File();
ULONG RLE_Read_File();
ULONG AVI_Read_File();
ULONG QT_Read_File();

LONG Is_SET_File();
LONG Is_IFF_File();
LONG Is_GIF_File();
LONG Is_TXT_File();
LONG Is_FLI_File();
LONG Is_DL_File();
LONG Is_PFX_File();
LONG Is_RLE_File();
LONG Is_AVI_File();
LONG Is_QT_File();

ULONG shm = 0;
#ifdef XSHM
XShmSegmentInfo im0_shminfo;
XShmSegmentInfo im1_shminfo;
XShmSegmentInfo im2_shminfo;
XImage *im0_Image = 0;
XImage *im1_Image = 0;
XImage *im2_Image = 0;
XImage *sh_Image = 0;
#endif

void PrintAction();

#ifdef VMS
/*      
 *      Provide the UNIX gettimeofday() function for VMS C.
 *      The timezone is currently unsupported.
 */

struct timeval {
    long tv_sec;
    long tv_usec;
};
 
struct timezone {
    int tz_minuteswest;
    int tz_dsttime;
};
 
int gettimeofday( tp, tzp)
struct timeval *tp;
struct timezone *tzp;
{
   long curr_time[2];   /* Eight byte VAX time variable */
   long jan_01_1970[2] = { 0x4BEB4000,0x7C9567} ;
   long diff[2];
   long result;
   long vax_sec_conv = 10000000;
 
   result = sys$gettim( &curr_time );
 
   result = lib$subx( &curr_time, &jan_01_1970, &diff);
 
   if ( tp != 0) {
       result = lib$ediv( &vax_sec_conv, &diff,
                          &(tp->tv_sec), &(tp->tv_usec) );
       tp->tv_usec = tp->tv_usec / 10;  /* convert 1.e-7 to 1.e-6 */
   }
   if ( tzp !=0) { tzp->tz_minuteswest = 0; tzp->tz_dsttime=0;}
 
   return ( 0);
}
#endif


/*
 * Global X11 display configuation variables
 *
 * These are set by X11_Pre_Setup();
 *
 */

LONG x11_error_possible = 0; /* -1 err occured. 0 no error. 1 err expected */
LONG x11_depth;
LONG x11_class;
LONG x11_bytes_pixel;
LONG x11_byte_order;
LONG x11_bits_per_pixel;
LONG x11_bitmap_pad;
LONG x11_pack_flag;
LONG x11_bitmap_unit;
LONG x11_bit_order;
LONG x11_cmap_flag;
LONG x11_cmap_size;
LONG x11_disp_bits;
LONG x11_cmap_type;
LONG x11_depth_mask;
LONG x11_display_type;
LONG x11_red_mask;
LONG x11_green_mask;
LONG x11_blue_mask;
LONG x11_red_shift;
LONG x11_green_shift;
LONG x11_blue_shift;
LONG x11_red_bits;
LONG x11_green_bits;
LONG x11_blue_bits;
LONG x11_black;
LONG x11_white;
LONG x11_verbose_flag;
LONG pod_max_colors;
LONG xa_user_visual;
LONG xa_user_class;
ULONG x11_kludge_1;

/*
 * Each animation is broken up into a series of individual actions.
 * For example, a gif image would become two actions, 1 to setup the
 * colormap and 1 to display the image.
 *
 * XA_ACTION is defined in xanim.h. 
 *
 * action_cnt is a global variable that points to the next unused action.
 * Currently, individual routines access this. This will change.
 *
 * action_start is a variable passed to the Read_Animation routines, It
 * keeps track of the 1st action available to routine.
 *
 */

/*
 * anim_type is one of IFF_,FLI_,GIF_,TXT_,FADE_ANIM. 
 *
 * merged_anim_flags is the or of all anims read in. FLI's anims need
 * only 1 buffer. IFF anims need two. This allows software to allocate
 * for the worst case.
 *
 */
ULONG xa_anim_type;
ULONG xa_merged_anim_flags;



/*
 * cmap keeps track of the current colors to the screen.
 *
 */
LONG cmap_true_to_332;
LONG cmap_true_to_gray;
LONG cmap_true_to_1st;
LONG cmap_true_to_all;
LONG cmap_true_map_flag;
LONG cmap_luma_sort;
LONG cmap_map_to_1st_flag;
LONG cmap_map_to_one_flag;
LONG cmap_play_nice;
LONG cmap_force_load;
LONG xa_allow_nice;
LONG cmap_hist_flag;
LONG cmap_dither_type;
LONG cmap_median_type;
LONG cmap_median_bits;
LONG cmap_use_combsort;
double xa_disp_gamma;
double xa_anim_gamma;
ULONG xa_gamma_flag;
USHORT xa_gamma_adj[256];
XA_CHDR *xa_chdr_start;
XA_CHDR *xa_chdr_cur;
XA_CHDR *xa_chdr_now;
XA_CHDR *xa_chdr_first;
USHORT *cmap_cache;
ULONG cmap_cache_size;
ULONG cmap_cache_bits;
ULONG cmap_cache_rmask;
ULONG cmap_cache_gmask;
ULONG cmap_cache_bmask;
XA_CHDR *cmap_cache_chdr;
SHORT cmap_floyd_error;

ULONG cmap_color_func;
ULONG cmap_sample_cnt;   /* sample anim every X many frames for colors */

/*
 * These are variables for HAM images
 *
 */
ULONG xa_ham_map_size;
ULONG *xa_ham_map;
XA_CHDR *xa_ham_chdr;
ULONG xa_ham_init;
/*
 * These are for converting TRUE images to PSEUDO
 *
 */
ULONG xa_r_shift,xa_g_shift,xa_b_shift;
ULONG xa_r_mask,xa_g_mask,xa_b_mask;
ULONG xa_gray_bits,xa_gray_shift;

ColorReg *xa_cmap = 0;
ULONG  xa_cmap_size,xa_cmap_off;
ULONG  *xa_map;
ULONG  xa_map_size,xa_map_off;

/*
 * Global variable to keep track of Anim type
 */
LONG filetype;
ULONG xa_title_flag;
char xa_title[256];


/*
 * Global variables to keep track of current width, height, num of colors and
 * number of bit planes respectively. 
 *
 * the max_ variable are used for worst case allocation. Are useful for Anims
 * that have multiple image sizes.
 *
 * image_size and max_image_size are imagex * imagey, etc.
 */
ULONG xa_image_size;
ULONG xa_max_image_size;
ULONG xa_imagex,xa_max_imagex;
ULONG xa_imagey,xa_max_imagey;
ULONG xa_imaged;

/*
 * Scaling Variable
 *
 */

ULONG xa_need_to_scale_b;
ULONG xa_need_to_scale_u;
float xa_scalex, xa_scaley;
float xa_bscalex, xa_bscaley;
ULONG xa_buff_x,xa_buff_y;		/* anim buffering size */
ULONG xa_allow_lace;
ULONG xa_allow_resizing; 		/* allow window resizing */
ULONG xa_disp_y, xa_max_disp_y;
ULONG xa_disp_x, xa_max_disp_x;
ULONG xa_disp_size;
ULONG xa_max_disp_size;
ULONG x11_display_x, x11_display_y;	/* max display size */
ULONG x11_window_x, x11_window_y;	/* current window size */
ULONG *xa_scale_row_buff;
ULONG xa_scale_row_size;
ULONG x11_expose_flag;

/* 
 * These variable keep track of where we are in the animation.
 * cur_file  ptr to the header of the current anim file. 
 * cur_floop keeps track of how many times we've looped a file.
 * cur_frame keeps track of which frame(action) we're on.
 *
 * xa_now_cycling and cycle_cnt are used for color cycling.
 *
 * file_is_started indicates whether this is the 1st time we've looped a file
 * or not. Is used to initialize variables and resize window if necessary.
 * 
 */
XA_ANIM_HDR *cur_file   = 0;
XA_ANIM_HDR *first_file = 0;
LONG xa_file_num;
LONG cur_floop,cur_frame;
LONG xa_cycle_cnt;      /* keeps track of number of cycling actions called */
LONG xa_now_cycling;    /* indicates that cycling is now in progress */
LONG xa_anim_cycling;   /* if set, allows cycling for animations */
LONG file_is_started;
int xa_fd;		/* Used if anim is being read from a file */
char *xa_codec_buf;
/*
 * Image buffers.
 * im_buff1 is used for double buffered anims(IFF).
 * xa_disp_buff is needed when the display is of a different format than the
 * double buffered images. (like HAM or TRUE_COLOR).
 *
 * xa_pic is a pointer to im_buff0 or im_buff1 during double buffering.
 * im_buff2 is used for dithered or HAM images
 */
char *im_buff0,*im_buff1,*im_buff2,*im_buff3;
char *xa_pic,*xa_disp_buff,*xa_scale_buff;
ULONG xa_disp_buff_size,xa_scale_buff_size;

/*
 * Variables for statistics
 *
 */
LONG xa_time_start;
LONG xa_time_end;
LONG xa_time_off;
LONG xa_no_disp;
LONG xa_time_flag;
LONG xa_time_av;
LONG xa_time_num;
struct timeval tv;


/* 
 * Global flags that are set on command line.
 */
LONG xa_buffer_flag;
LONG x11_shared_flag;
LONG xa_file_flag;
LONG fade_flag,fade_time;
LONG xa_noresize_flag;
LONG xa_optimize_flag;
LONG xa_pixmap_flag;
LONG xa_dither_flag;
LONG xa_pack_flag;
LONG xa_debug;
LONG xa_verbose;

LONG xa_loop_each_flag;
LONG xa_pingpong_flag;
LONG xa_jiffy_flag;
ULONG xa_speed_scale;

LONG xa_anim_flags;
LONG xa_anim_holdoff;
LONG xa_anim_status;
LONG xa_anim_ready = FALSE;
LONG xa_use_depth_flag;

LONG xa_exit_flag;

XA_PAUSE *xa_pause_hdr=0;


/*
 * act is a global pointer to the current action.
 *
 */
XA_ACTION *act;

void
Usage_Quick()
{
  fprintf(stderr,"Usage:\n");
  fprintf(stderr,"   XAnim [options] anim [ [options] anim ... ]\n");
  fprintf(stderr,"   XAnim -h   for more detailed help.\n");
  TheEnd();
}
void
Usage_Default_TF(flag,justify)
ULONG flag,justify;
{
  if (justify == 1) fprintf(stderr,"            ");
  if (flag == TRUE) fprintf(stderr," default is on.\n");
  else fprintf(stderr," default is off.\n");
}

void
Usage_Default_Num(num,justify)
ULONG num,justify;
{
  if (justify == 1) fprintf(stderr,"            ");
  fprintf(stderr," default is %ld.\n",num);
}

/*
 * This function attempts to expain XAnim's usage if the command line
 * wasn't correct.
 */
void Usage()
{
 fprintf(stderr,"Usage:\n\n");
 fprintf(stderr,"xanim [+V#] [ [+|-]opts ...] animfile [ [ [+|-opts] animfile] ... ]\n");
 fprintf(stderr,"\n");
#ifdef VMS
 fprintf(stderr,"VMS users need to enclose opts in double qotes: \"+Cn\".\n");
 fprintf(stderr,"\n");
#endif
 if (DEFAULT_PLUS_IS_ON == TRUE) 
      fprintf(stderr,"A + turns an option on and a - turns it off.\n");
 else fprintf(stderr,"A - turns an option on and a + turns it off.\n");
 fprintf(stderr,"\n");
 fprintf(stderr,"Options:\n");
 fprintf(stderr,"\n  C[copts]  Color SubMenu\n");
 fprintf(stderr,"       1    Create cmap from 1st TrueColor frame. Map\n");
 fprintf(stderr,"            the rest to this first cmap.(Could be SLOW)\n");
 fprintf(stderr,"       3    Convert TrueColor anims to 332(StaticColor).\n");
 Usage_Default_TF(DEFAULT_TRUE_TO_332,1);
 fprintf(stderr,"       a    Remap  all images to single new cmap.\n");
 Usage_Default_TF(DEFAULT_CMAP_MAP_TO_ONE,1);
 fprintf(stderr,"       d    Use floyd-steinberg dithering.\n");
 Usage_Default_TF((DEFAULT_CMAP_DITHER_TYPE==CMAP_DITHER_FLOYD),1);
 fprintf(stderr,"       f    Forcibly remap to 1st cmap\n");
 Usage_Default_TF(DEFAULT_CMAP_MAP_TO_1ST,1);
 fprintf(stderr,"       F4   Better(?) Color mapping for TrueColor anims.\n");
 Usage_Default_TF(FALSE,1);
 fprintf(stderr,"       g    Convert TrueColor anims to gray scale.\n");
 Usage_Default_TF(DEFAULT_TRUE_TO_GRAY,1);
 fprintf(stderr,"       h    Use histogram to aid in color reduction.\n");
 Usage_Default_TF(DEFAULT_CMAP_HIST_FLAG,1);
 fprintf(stderr,"       n    Be Nice: allocate colors from Default cmap.\n");
 Usage_Default_TF(DEFAULT_CMAP_PLAY_NICE,1);
 fprintf(stderr,"\n  G[gopts]  Gamma SubMenu\n");
 fprintf(stderr,"       a#   Set gamma of animation. Default %f\n",
							(DEFAULT_ANIM_GAMMA));
 fprintf(stderr,"       d#   Set gamma of display. Default %f\n",
							(DEFAULT_DISP_GAMMA));
 fprintf(stderr,"\n  M[mopts]  Median-Cut SubMenu\n");
 fprintf(stderr,"       a    compute box color from average of box.\n");
 Usage_Default_TF( (DEFAULT_CMAP_MEDIAN_TYPE==CMAP_MEDIAN_SUM),1);
 fprintf(stderr,"       c    compute box color as center of box.\n");
 Usage_Default_TF( (DEFAULT_CMAP_MEDIAN_TYPE==CMAP_MEDIAN_CENTER),1);
 fprintf(stderr,"       b#   Truncate rgb to # bits.\n");
 Usage_Default_Num(CMAP_CACHE_MAX_BITS,1);
 fprintf(stderr,"\n  S[sopts]  Scaling and Sizing SubMenu\n");
 fprintf(stderr,"       i    Half the height of IFF anims if Interlaced.\n");
 Usage_Default_TF(DEFAULT_ALLOW_LACE_FLAG,1);
 fprintf(stderr,"       n    Prevents X11 window from resizing to match anim's size.\n"); 
 Usage_Default_TF(DEFAULT_NORESIZE_FLAG,1);
 fprintf(stderr,"       r    Allow user to resize anim on the fly.\n");
 Usage_Default_TF(DEFAULT_ALLOW_RESIZING,1);
 fprintf(stderr,"       s#   Scale size of anim by # before displaying.\n");
 fprintf(stderr,"       h#   Scale width of anim by # before displaying.\n");
 fprintf(stderr,"       v#   Scale height of anim by # before displaying.\n");
 fprintf(stderr,"       x#   Scale anim to have width # before displaying.\n");
 fprintf(stderr,"       y#   Scale anim to have height # before displaying.\n");
 fprintf(stderr,"       c    Copy display scaling factors to buffer scaling factors\n");
 fprintf(stderr,"       S#   Scale size of anim by # before buffering.\n");
 fprintf(stderr,"       H#   Scale width of anim by # before buffering.\n");
 fprintf(stderr,"       V#   Scale height of anim by # before buffering.\n");
 fprintf(stderr,"       X#   Scale anim to have width # before buffering.\n");
 fprintf(stderr,"       Y#   Scale anim to have height # before buffering.\n");
 fprintf(stderr,"       C    Copy buffer scaling factors to display scaling factors\n");
 fprintf(stderr,"\n  Normal Options\n");
 fprintf(stderr,"       b    Uncompress and buffer images ahead of time.\n"); 
 Usage_Default_TF(DEFAULT_BUFF_FLAG,1);
#ifdef XSHM
 fprintf(stderr,"       B    Use X11 Shared Memory Extention if supported.\n"); 
 Usage_Default_TF(FALSE,1);
#endif
 fprintf(stderr,"       c    disable looping for nonlooping iff anims.\n"); 
 Usage_Default_TF(DEFAULT_IFF_LOOP_OFF,1);
 fprintf(stderr,"       d#   debug. 0(off) to 5(most) for level of detail.\n"); 
 Usage_Default_Num(DEFAULT_DEBUG,1);
 fprintf(stderr,"       F    Floyd-Steinberg dithering for Mono displays only.\n");
 Usage_Default_TF(DEFAULT_DITHER_FLAG,1);
 fprintf(stderr,"       f    Don't load anims into memory, but read from file as needed\n"); 
 Usage_Default_TF(DEFAULT_BUFF_FLAG,1);
 fprintf(stderr,"       j#   # is number of milliseconds between frames.\n");
 fprintf(stderr,"	     if 0 then default depends on the animation.\n");
 Usage_Default_Num(DEFAULT_JIFFY_FLAG,1);
 fprintf(stderr,"       l#   loop anim # times before moving on.\n");
 Usage_Default_Num(DEFAULT_LOOPEACH_FLAG,1);
 fprintf(stderr,"       lp#  ping-pong anim # times before moving on.\n");
 Usage_Default_Num(DEFAULT_PINGPONG_FLAG,1);
 fprintf(stderr,"       N    No display. Useful for benchmarking.\n");
 fprintf(stderr,"       o    turns on certain optimizations. See readme.\n"); 
 Usage_Default_TF(DEFAULT_OPTIMIZE_FLAG,1);
 fprintf(stderr,"       p    Use Pixmap instead of Image in X11.\n"); 
 Usage_Default_TF(DEFAULT_PIXMAP_FLAG,1);
 fprintf(stderr,"       r    Allow color cycling for IFF single images.\n");
 Usage_Default_TF(DEFAULT_CYCLE_IMAGE_FLAG,1);
 fprintf(stderr,"       R    Allow color cycling for IFF anims.\n");
 Usage_Default_TF(DEFAULT_CYCLE_ANIM_FLAG,1);
 fprintf(stderr,"       T#   Title Option. See readme.\n");
 fprintf(stderr,"       v    verbose mode.\n"); 
 fprintf(stderr,"       V#   Use Visual #. # is obtained by +X option.\n"); 
 fprintf(stderr,"       X    X11 verbose mode. Display Visual information.\n");
 fprintf(stderr,"       Z    Have XAnim exit after playing cmd line.\n");
 Usage_Default_TF(DEFAULT_VERBOSE,1);
 fprintf(stderr,"\n");
 fprintf(stderr,"Window commands.\n");
 fprintf(stderr,"\n");
 fprintf(stderr,"        q    quit.\n");
 fprintf(stderr,"        Q    Quit.\n");
 fprintf(stderr,"        g    Stop color cycling.\n");
 fprintf(stderr,"        r    Restore original Colors(useful after g).\n");
 fprintf(stderr,"    <space>  Toggle. Starts/Stops animation.\n");
 fprintf(stderr,"        ,    Single step back one frame.\n");
 fprintf(stderr,"        .    Single step forward one frame.\n");
 fprintf(stderr,"        <    Go back to start of previous anim.\n");
 fprintf(stderr,"        >    Go forward to start of next anim.\n");
 fprintf(stderr,"        m    Single step back one frame staying within anim.\n");
 fprintf(stderr,"        /    Single step forward one frame staying within anim.\n");
 fprintf(stderr,"        -    Increase animation playback speed.\n");
 fprintf(stderr,"        =    Decrease animation playback speed.\n");
 fprintf(stderr,"        0    Reset animation playback speed to original values.\n");
 fprintf(stderr,"\n");
 fprintf(stderr,"Mouse Buttons.\n");
 fprintf(stderr,"\n");
 fprintf(stderr,"      <Left> Single step back one frame.\n");
 fprintf(stderr,"    <Middle> Toggle. Starts/Stops animation.\n");
 fprintf(stderr,"     <Right> Single step forward one frame.\n");
 fprintf(stderr,"\n");
 exit(0);
}

int main(argc, argv)
int argc;
char *argv[];
{
 char *filename,*in;
 LONG i,j;

/* 
 * Initialize global variables.
 */

 cmap_color_func = 4;
 cmap_sample_cnt = 5; /* default value */

#ifdef XSHM
 im0_shminfo.shmaddr = 0;
 im1_shminfo.shmaddr = 0;
 im2_shminfo.shmaddr = 0;
#endif
 im_buff0 = im_buff1 = im_buff2 = im_buff3 = 0;
 xa_disp_buff = 0;
 xa_disp_buff_size = 0;
 xa_scale_row_buff = 0;
 xa_scale_row_size = 0;
 xa_scale_buff	= 0;
 xa_scale_buff_size = 0;
 xa_imagex	= 0;
 xa_imagey	= 0;
 xa_disp_x	= 0;
 xa_disp_y	= 0;
 xa_scalex	= 1.0;
 xa_scaley	= 1.0;
 xa_buff_x	= 0;
 xa_buff_y	= 0;
 xa_bscalex	= 1.0;
 xa_bscaley	= 1.0;
 xa_need_to_scale_b = 0;
 xa_need_to_scale_u = 0;
 xa_max_imagex	= 0;
 xa_max_imagey	= 0;
 xa_max_disp_x	= 0;
 xa_max_disp_y	= 0;
 xa_anim_flags		= 0;
 xa_merged_anim_flags	= 0;
 x11_pack_flag	= FALSE;
 x11_expose_flag = FALSE;
 x11_error_possible = 0;

 first_file = cur_file = 0;
 xa_file_num = -1;

 xa_anim_holdoff	= TRUE;
 xa_anim_status		= XA_UNSTARTED;
 xa_anim_ready		= FALSE;

 xa_fd			= -1;
 xa_codec_buf		= 0;
 xa_buffer_flag		= DEFAULT_BUFF_FLAG;
 if (xa_buffer_flag == TRUE) xa_file_flag = FALSE;
 else xa_file_flag	= DEFAULT_FILE_FLAG;
 x11_shared_flag	= TRUE;
 xa_pack_flag		= DEFAULT_PACK_FLAG;
 xa_noresize_flag	= DEFAULT_NORESIZE_FLAG;
 xa_verbose		= DEFAULT_VERBOSE;
 xa_debug		= DEFAULT_DEBUG;
 xa_anim_cycling	= DEFAULT_CYCLE_ANIM_FLAG;
 xa_allow_lace		= DEFAULT_ALLOW_LACE_FLAG;
 xa_allow_resizing	= DEFAULT_ALLOW_RESIZING;
 xa_optimize_flag	= DEFAULT_OPTIMIZE_FLAG;
 xa_pixmap_flag		= DEFAULT_PIXMAP_FLAG;
 xa_dither_flag		= DEFAULT_DITHER_FLAG;
 xa_loop_each_flag	= DEFAULT_LOOPEACH_FLAG;
 xa_pingpong_flag	= DEFAULT_PINGPONG_FLAG;
 xa_jiffy_flag		= DEFAULT_JIFFY_FLAG;
 xa_speed_scale		= 0x01 << 16;
 x11_verbose_flag	= DEFAULT_X11_VERBOSE_FLAG;
 x11_kludge_1		= FALSE;
 cmap_luma_sort		= DEFAULT_CMAP_LUMA_SORT;
 cmap_map_to_1st_flag	= DEFAULT_CMAP_MAP_TO_1ST;
 cmap_map_to_one_flag	= DEFAULT_CMAP_MAP_TO_ONE;
 cmap_play_nice		= DEFAULT_CMAP_PLAY_NICE;
 cmap_force_load	= FALSE;
 xa_allow_nice		= TRUE;
 cmap_hist_flag		= DEFAULT_CMAP_HIST_FLAG;
 cmap_dither_type	= DEFAULT_CMAP_DITHER_TYPE;

 cmap_median_type	= DEFAULT_CMAP_MEDIAN_TYPE;
 cmap_median_bits	= 6;
 cmap_use_combsort	= TRUE;
 cmap_floyd_error	= 256; 
 cmap_cache		= 0;
 cmap_cache_size	= 0;
 cmap_cache_bits	= 0;
 cmap_cache_rmask	= 0;
 cmap_cache_gmask	= 0;
 cmap_cache_bmask	= 0;
 cmap_cache_chdr	= 0;
 xa_disp_gamma		= DEFAULT_DISP_GAMMA;
 xa_anim_gamma		= DEFAULT_ANIM_GAMMA;
 xa_gamma_flag		= FALSE;

 xa_title_flag		= DEFAULT_XA_TITLE_FLAG;
 xa_exit_flag		= DEFAULT_XA_EXIT_FLAG;

 xa_chdr_start		= 0;
 xa_chdr_cur		= 0;
 xa_chdr_now		= 0;
 xa_chdr_first		= 0;
 xa_cmap		= 0;
 xa_cmap_size		= 0;
 xa_cmap_off		= 0;
 xa_map			= 0;
 xa_map_size		= 0;
 xa_map_off		= 0;
 xa_time_start		= 0;
 xa_time_end		= 0;
 xa_time_av 		= 0;
 xa_time_num		= 0;
 xa_no_disp		= FALSE;
 xa_time_flag		= FALSE;
 pod_max_colors		= 0;
 xa_r_shift = xa_g_shift = xa_b_shift = 0;
 xa_r_mask = xa_g_mask = xa_b_mask = 0;
 xa_gray_bits = xa_gray_shift = 0;
 xa_ham_map_size = 0;
 xa_ham_map = 0;
 xa_ham_chdr = 0;
 xa_ham_init = 0;
 fli_pad_kludge = FALSE;
 xa_pause_hdr = 0;

 XA_Time_Init();
 xa_gamma_flag = CMAP_Gamma_Adjust(xa_gamma_adj,xa_disp_gamma,xa_anim_gamma);

 if (DEFAULT_IFF_LOOP_OFF  == TRUE) xa_anim_flags |= ANIM_NOLOOP;
 if (DEFAULT_CYCLE_IMAGE_FLAG == TRUE) xa_anim_flags |= ANIM_CYCLE;

/* What REV are we running
 */
 fprintf(stderr,"XAnim Rev %2.2f.%ld by Mark Podlipec (c) 1991-1994\n",DA_REV,DA_MINOR_REV);

/* quick command line check.
 */
 if (argc<2) Usage_Quick();

/* setup for dying time.
 */
 signal(SIGINT,Hard_Death);

 /* pre-check for user visual */
 xa_user_visual = -1;
 xa_user_class  = -1;
 for(i=1;i<argc;i++)
 {
   in = argv[i];

   if ( ((in[0]=='-') || (in[0]=='+')) && (in[1]=='V') )
   {
     if ( (in[2] >= '0') && (in[2] <= '9') )  /* number */
		xa_user_visual = atoi(&in[2]);
     else	xa_user_class = XA_Get_Class( &in[2] );
   }
   else if ( (in[0]=='-') && (in[1]=='X') ) x11_verbose_flag = FALSE;
   else if ( (in[0]=='+') && (in[1]=='X') ) x11_verbose_flag = TRUE;
   else if ( (in[0]=='+') && (in[1]=='B') ) x11_shared_flag = TRUE;
   else if ( (in[0]=='+') && (in[1]=='P') )
   {
     pod_max_colors = atoi(&in[2]); /* POD Testing only */
   }
 }
 /* PreSet of X11 Display to find out what we're dealing with
  */
 X11_Pre_Setup(&argc, argv, xa_user_visual, xa_user_class);
 if (xa_allow_nice == FALSE) cmap_play_nice = FALSE;

 /* Visual Dependent switches and flags */
 if (x11_display_type & XA_X11_TRUE)
 {
   cmap_true_to_332  = FALSE; cmap_true_to_gray = FALSE;
   cmap_true_to_1st  = FALSE; cmap_true_to_all  = FALSE;
   cmap_true_map_flag = FALSE;
 }
 else if (x11_display_type & XA_X11_COLOR)
 {
   cmap_true_to_332  = DEFAULT_TRUE_TO_332;
   cmap_true_to_gray = DEFAULT_TRUE_TO_GRAY;
   cmap_true_to_1st  = DEFAULT_TRUE_TO_1ST;
   cmap_true_to_all  = DEFAULT_TRUE_TO_ALL;
   if (cmap_true_to_1st || cmap_true_to_all) cmap_true_map_flag = TRUE;
   else cmap_true_map_flag = DEFAULT_TRUE_MAP_FLAG;
 }
 else { cmap_true_to_332  = FALSE; cmap_true_to_gray = TRUE; 
        cmap_true_to_1st  = FALSE; cmap_true_to_all  = FALSE;
        cmap_true_map_flag = FALSE;  }

 xa_time_start = XA_Time_Read();

/* Parse command line.
 */
 for(i=1; i < argc; i++)
 {
   in = argv[i];
   if ( (in[0] == '-') || (in[0] == '+') )
   {
     LONG len,opt_on;

     if (in[0] == '-') opt_on = FALSE;
     else opt_on = TRUE;
     /* if + turns off then reverse opt_on */
     if (DEFAULT_PLUS_IS_ON == FALSE) opt_on = (opt_on==TRUE)?FALSE:TRUE;

     len = strlen(argv[i]);
     j = 1;
     while( (j < len) && (in[j] != 0) )
     {
       switch(in[j])
       {
        case 'C':   /* colormap options sub menu */
	  {
	    ULONG exit_flag = FALSE;
	    j++;
	    while( (exit_flag == FALSE) && (j<len) )
	    {
		switch(in[j])
		{
		  case 's':
			j++; cmap_sample_cnt = XA_Read_Int(in,&j);
			break;
		  case 'F':
			j++; cmap_color_func = XA_Read_Int(in,&j);
			break;
		  case '1':
 			if (   (x11_display_type & XA_X11_TRUE)
 			    || (x11_display_type & XA_MONOCHROME) ) 
							opt_on = FALSE;
			cmap_true_to_1st  = opt_on;
			if (cmap_true_to_1st == TRUE)
			{
			  cmap_true_to_gray = FALSE; cmap_true_to_332  = FALSE;
			  cmap_true_to_all  = FALSE; cmap_true_map_flag = TRUE;
			}
			j++; break;
		  case 'A':
 			if (   (x11_display_type & XA_X11_TRUE)
 			    || (x11_display_type & XA_MONOCHROME) ) 
							opt_on = FALSE;
			cmap_true_to_all  = opt_on;
			if (cmap_true_to_all == TRUE)
			{
			  cmap_true_to_gray = FALSE; cmap_true_to_332  = FALSE;
			  cmap_true_to_1st  = FALSE; cmap_true_map_flag = TRUE;
			}
			j++; break;
		  case '3':
 			if (   (x11_display_type & XA_X11_TRUE)
 			    || (!(x11_display_type & XA_X11_COLOR))
 			    || (x11_display_type & XA_MONOCHROME) ) 
							opt_on = FALSE;
			cmap_true_to_332  = opt_on;
			if (opt_on == TRUE)
			{
			  cmap_true_to_gray = FALSE; cmap_true_to_1st  = FALSE;
			  cmap_true_to_all  = FALSE;
			}
			j++; break;
		  case 'g':
 			if (x11_display_type & XA_X11_TRUE) opt_on = FALSE;
			cmap_true_to_gray  = opt_on;
			if (opt_on == TRUE)
			{
			  cmap_true_to_332 = FALSE; cmap_true_to_1st = FALSE;
			  cmap_true_to_all = FALSE;
			}
			j++; break;
		  case 'a': cmap_map_to_one_flag = opt_on; j++; break;
		  case 'c': cmap_force_load = opt_on; j++; break;
		  case 'd': cmap_dither_type = CMAP_DITHER_FLOYD; j++; break;
		  case 'l': cmap_luma_sort  = opt_on; j++; break;
		  case 'f': cmap_map_to_1st_flag = opt_on; j++; break;
		  case 'm': cmap_true_map_flag = opt_on; j++; break;
		  case 'n': j++;
		    if (xa_allow_nice == TRUE) cmap_play_nice  = opt_on;
		    break;
		  case 'h': cmap_hist_flag  = opt_on; j++; break;
		  default: exit_flag = TRUE;
		}
	    }
	  }
          break;
	case 'G': /* gamma options sub-menu */ 
	  {
	    ULONG exit_flag = FALSE;
	    j++;
	    while( (exit_flag == FALSE) && (j<len) )
	    {
		switch(in[j])
		{
		  case 'a': /* set anim gamma */
			j++;
			xa_anim_gamma = XA_Read_Float(in,&j);
			if (xa_anim_gamma <= 0.0001) xa_anim_gamma = 0.0;
			xa_gamma_flag = CMAP_Gamma_Adjust(xa_gamma_adj,
						xa_disp_gamma,xa_anim_gamma);
			break;
		  case 'd': /* set display gamma */
			j++;
			xa_disp_gamma = XA_Read_Float(in,&j);
			if (xa_disp_gamma <= 0.0001) xa_disp_gamma = 0.0;
			xa_gamma_flag = CMAP_Gamma_Adjust(xa_gamma_adj,
						xa_disp_gamma,xa_anim_gamma);
			break;
		  default: exit_flag = TRUE;
		}
	    }
	  }
          break;

	case 'M': /* median cut options sub-menu */ 
	  {
	    ULONG exit_flag = FALSE;
	    j++;
	    while( (exit_flag == FALSE) && (j<len) )
	    {
		switch(in[j])
		{
		  case 'a': cmap_median_type = CMAP_MEDIAN_SUM; j++; break;
		  case 'c': cmap_median_type = CMAP_MEDIAN_CENTER; j++; break;
		  /* POD Testing only */
		  case 'e':
			j++; cmap_floyd_error = XA_Read_Int(in,&j);
			if (cmap_floyd_error <= 0) cmap_floyd_error = 0;
			break;
		  case 'b':
			j++; cmap_median_bits = XA_Read_Int(in,&j);
			if (cmap_median_bits <= 5) cmap_median_bits = 5;
			if (cmap_median_bits >  8) cmap_median_bits = 8;
			break;
		  /* POD benchmark only */
		  case 'q': if (opt_on == TRUE) cmap_use_combsort = FALSE;
			    else cmap_use_combsort = TRUE;
			    j++; break;
		  default: exit_flag = TRUE;
		}
	    }
	  }
          break;
        case 'B':
                x11_shared_flag = opt_on;	j++;
                break;
        case 'b':
                xa_buffer_flag = opt_on;	j++;
		if (xa_buffer_flag==TRUE) xa_file_flag = FALSE;
                break;
        case 'c':
                if (opt_on==TRUE) xa_anim_flags |= ANIM_NOLOOP;
                else xa_anim_flags &= (~ANIM_NOLOOP);
                j++; break;
        case 'd':
                j++; xa_debug = XA_Read_Int(in,&j);
                if (xa_debug <= 0) xa_debug = 0;
		break;
        case 'f':
                xa_file_flag = opt_on;	j++;
		if (xa_file_flag==TRUE) xa_buffer_flag = FALSE;
		break;
        case 'F':
                xa_dither_flag = opt_on;	j++;	break;
        case 'h':
                Usage(); break;
	case 'J': 
		j++; xa_speed_scale = XA_Read_Int(in,&j);
		if (xa_speed_scale == 0) xa_speed_scale = 1;
		if (xa_speed_scale > 1000) xa_speed_scale = 1000;
		if (opt_on == TRUE) xa_speed_scale <<= 16;
		else	xa_speed_scale = (0x01 << 16) / xa_speed_scale;
		break;
        case 'j':
                j++;
		if ( (in[j] >= '0') || (in[j] <= '9') )
		{ 
                  xa_jiffy_flag = XA_Read_Int(in,&j);
                  if (xa_jiffy_flag <= 0) xa_jiffy_flag = 1;
		}
		else xa_jiffy_flag = 0; /* off */
                break;
        case 'k':
		{ ULONG tmp;
                  j++;
		  if ( (in[j] >= '0') || (in[j] <= '9') )
		  { 
                    tmp = XA_Read_Int(in,&j);
                    if (tmp==1) fli_pad_kludge = opt_on;
		  }
		}
                break;
        case 'l':
		j++; 
		if (in[j] == 'p')
		{
		  xa_pingpong_flag = opt_on; j++;
		}
		else xa_pingpong_flag = FALSE;
                xa_loop_each_flag = XA_Read_Int(in,&j);
                if (xa_loop_each_flag<=0) xa_loop_each_flag = 1;
		break;
        case 'N':
		xa_no_disp = opt_on;
                xa_time_flag = opt_on;	j++;	break;
        case 'o':
                xa_optimize_flag = opt_on; j++;	break;
        case 'p':
                xa_pixmap_flag = opt_on; j++;
		if (opt_on==TRUE) xa_anim_flags |= ANIM_PIXMAP;
		else xa_anim_flags &= ~ANIM_PIXMAP;
                break;
        case 'P':
                j++; pod_max_colors = XA_Read_Int(in,&j);
                if (pod_max_colors <= 0) pod_max_colors = 0;
		break;
        case 'r':
                if (opt_on == TRUE)	xa_anim_flags |= ANIM_CYCLE;
                else			xa_anim_flags &= (~ANIM_CYCLE);
                j++;
                break;
        case 'R':
                xa_anim_cycling = opt_on; j++;	break;
        case 'S':
	  {
	    ULONG exit_flag = FALSE;
	    j++;
	    while( (exit_flag==FALSE) && (j<len) )
	    {
		switch(in[j])
		{
		  case 'i': xa_allow_lace = opt_on;  j++; break;
		  case 'n': xa_noresize_flag = opt_on;  j++; break;
		  case 'r': xa_allow_resizing = opt_on; j++; break;
		  case 'c': /* copy display scaling to buffer scaling */
		    j++;
		    xa_bscalex = xa_scalex; xa_bscaley = xa_scaley;
		    xa_buff_x = xa_disp_x; xa_buff_y = xa_disp_y;
		    break;
		  case 's': /* scale anim display size */
		    j++;
                    xa_scalex = XA_Read_Float(in,&j);
		    if (xa_scalex == 0.0) xa_scalex = 1.0;
		    xa_scaley = xa_scalex;
		    xa_disp_x = xa_disp_y = 0; break;
		  case 'x':  /* set anim display x size */
		    j++; xa_scalex = 1.0;
                    xa_disp_x = XA_Read_Int(in,&j);
		    break;
		  case 'y':  /* set anim display y size */
		    j++; xa_scaley = 1.0;
                    xa_disp_y = XA_Read_Int(in,&j);
		    break;
		  case 'h':  /* scale anim display horizontally */
		    j++;
                    xa_scalex = XA_Read_Float(in,&j);
		    if (xa_scalex == 0.0) xa_scalex = 1.0;
		    xa_disp_x = 0; break;
		  case 'v':  /* scale anim display vertically */
		    j++;
                    xa_scaley = XA_Read_Float(in,&j);
		    if (xa_scaley == 0.0) xa_scaley = 1.0;
		    xa_disp_y = 0; break;
		  case 'C': /* copy buffer scaling to display scaling */
		    j++;
		    xa_scalex = xa_bscalex; xa_scaley = xa_bscaley;
		    xa_disp_x = xa_buff_x; xa_disp_y = xa_buff_y;
		    break;
		  case 'S': /* scale anim buffering size */
		    j++;
                    xa_bscalex = XA_Read_Float(in,&j);
		    if (xa_bscalex == 0.0) xa_bscalex = 1.0;
		    xa_bscaley = xa_bscalex;
		    xa_buff_x = xa_buff_y = 0; break;
		  case 'X':  /* set anim buffering x size */
		    j++; xa_bscalex = 1.0;
                    xa_buff_x = XA_Read_Int(in,&j);
		    break;
		  case 'Y':  /* set anim buffering y size */
		    j++; xa_bscaley = 1.0;
                    xa_buff_y = XA_Read_Int(in,&j);
		    break;
		  case 'H':  /* scale anim buffering horizontally */
		    j++;
                    xa_bscalex = XA_Read_Float(in,&j);
		    if (xa_bscalex == 0.0) xa_bscalex = 1.0;
		    xa_buff_x = 0; break;
		  case 'V':  /* scale anim buffering vertically */
		    j++;
                    xa_bscaley = XA_Read_Float(in,&j);
		    if (xa_bscaley == 0.0) xa_bscaley = 1.0;
		    xa_buff_y = 0; break;
		  default: exit_flag = TRUE;
		}
	    }
	  }
	  break;
        case 't':
                xa_time_flag = opt_on;	j++;	break;
        case 'T':
                j++; xa_title_flag = XA_Read_Int(in,&j);
                if (xa_title_flag > 2) xa_title_flag = 2;
		break;
        case 'v':
                xa_verbose = opt_on;	j++;	break;
        case 'X':
		debug("ShowVisuals omitted.\n"); j++; break;
        case 'V':
		j += len; break;   /* ignore reset and move on */
        case 'Z':
	  {
	    ULONG exit_flag = FALSE;
	    j++;
	    while( (exit_flag==FALSE) && (j<len) )
	    { ULONG tmp;
		switch(in[j])
		{
		  case 'e': xa_exit_flag = opt_on;      j++;    break;
		  case 'p':
			j++; tmp = XA_Read_Int(in,&j);
			XA_Add_Pause(tmp);
			break;
		}
	    }
	  }
	  break;
        case '-':
                opt_on = (DEFAULT_PLUS_IS_ON==TRUE)?FALSE:TRUE; j++;	break;
        case '+':
                opt_on = (DEFAULT_PLUS_IS_ON==TRUE)?TRUE:FALSE; j++;	break;
        default:
                Usage_Quick();
       } /* end of option switch */
     } /* end of loop through options */
   } /* end of if - */
   else 
   /* If no hyphen in front of argument, assume it's a file.
    */
   { ULONG result;
     filename = argv[i];

     /* Visual Dependent switches and flags */
     if (x11_display_type & XA_X11_TRUE)
     {
       cmap_true_to_332  = cmap_true_to_gray = FALSE;
       cmap_true_to_1st  = cmap_true_to_all  = cmap_true_map_flag = FALSE;
     }
     else if (!(x11_display_type & XA_X11_COLOR))
     { cmap_true_to_gray = TRUE; cmap_true_to_332  = FALSE;
       cmap_true_to_1st  = cmap_true_to_all  = cmap_true_map_flag = FALSE;
     }
    
     if ( (x11_display_type == XA_MONOCHROME) || (xa_pack_flag == TRUE) )
       xa_use_depth_flag = FALSE;
     else
       xa_use_depth_flag = TRUE;
        /* default is FLI  */
     cur_file = Get_Anim_Hdr(cur_file,filename);
     xa_anim_type = Determine_Anim_Type(filename);
     cur_file->anim_type = xa_anim_type;
     cur_file->anim_flags = xa_anim_flags;
     if (x11_display_type == XA_MONOCHROME) xa_optimize_flag = FALSE;
     switch(xa_anim_type)
     {
        case IFF_ANIM:
	  if (xa_verbose) fprintf(stderr,"Reading IFF File %s\n",filename);
	  result = IFF_Read_File(filename,cur_file);
	  break;
        case GIF_ANIM:
	  if (xa_verbose) fprintf(stderr,"Reading GIF File %s\n",filename);
	  result = GIF_Read_Anim(filename,cur_file);
	  break;
        case TXT_ANIM:
	  if (xa_verbose) fprintf(stderr,"Reading TXT File %s\n",filename);
	  result = TXT_Read_File(filename,cur_file);
	  break;
        case FLI_ANIM:
	  if (xa_verbose) fprintf(stderr,"Reading FLI File %s\n",filename);
	  result = Fli_Read_File(filename,cur_file);
	  break;
        case DL_ANIM:
	  if (xa_verbose) fprintf(stderr,"Reading DL File %s\n",filename);
	  result = DL_Read_File(filename,cur_file);
	  break;
        case PFX_ANIM:
	  if (xa_verbose) fprintf(stderr,"Reading PFX File %s\n",filename);
	  result = PFX_Read_File(filename,cur_file);
	  break;
/*        case SET_ANIM:
	  if (xa_verbose) fprintf(stderr,"Reading SET File %s\n",filename);
	  result = SET_Read_File(filename,cur_file);
	  break; */
        case RLE_ANIM:
	  if (xa_verbose) fprintf(stderr,"Reading RLE File %s\n",filename);
	  result = RLE_Read_File(filename,cur_file);
	  break;
        case AVI_ANIM:
	  if (xa_verbose) fprintf(stderr,"Reading AVI File %s\n",filename);
	  result = AVI_Read_File(filename,cur_file);
	  break;
        case QT_ANIM:
	  if (xa_verbose) fprintf(stderr,"Reading QT File %s\n",filename);
	  result = QT_Read_File(filename,cur_file);
	  break;
        case NOFILE_ANIM:
	  fprintf(stderr,"File %s not found\n",filename);
	  result = FALSE;
	  break;
        default:
	  fprintf(stderr,"Unknown or unsupported animation type: %s\n",
								filename);
	  result = FALSE;
	  break;
      } 
      if (result == FALSE) cur_file = Return_Anim_Hdr(cur_file);
      else
      { ULONG tmpx,tmpy;
        /* Setup up anim header.  */
        cur_file->loop_num = xa_loop_each_flag;

	cur_file->pause_lst = xa_pause_hdr;
	xa_pause_hdr = 0;

	xa_imagex = cur_file->imagex;
	xa_imagey = cur_file->imagey;
	if (xa_imagex > xa_max_imagex) xa_max_imagex = xa_imagex;
	if (xa_imagey > xa_max_imagey) xa_max_imagey = xa_imagey;

	/* Handle Buffer Scaling Here */
	if ( (xa_buff_x != 0) && (xa_buff_y != 0) )
		{tmpx = xa_buff_x; tmpy = xa_buff_y;}
	else if (xa_buff_x != 0) /* if just x, then adjust y */
		{tmpx = xa_buff_x; tmpy = (xa_imagey * xa_buff_x) / xa_imagex;}
	else if (xa_buff_y != 0) /* if just y, then adjust x */
		{tmpy = xa_buff_y; tmpx = (xa_imagex * xa_buff_y) / xa_imagey;}
	else
	{
		/* handle any scaling */
	  tmpx = (ULONG)((float)(xa_imagex) * xa_bscalex);
	  if (tmpx == 0) tmpx = xa_imagex;
	  tmpy = (ULONG)((float)(xa_imagey) * xa_bscaley);
	  if (tmpy == 0) tmpy = xa_imagey;
	}
	cur_file->buffx = tmpx;
	cur_file->buffy = tmpy;

		/* Handle Display Scaling Here */
	if ( (xa_disp_x != 0) && (xa_disp_y != 0) ) 
		{tmpx = xa_disp_x; tmpy = xa_disp_y;}
	else if (xa_disp_x != 0) /* if just x, then adjust y */
		{tmpx = xa_disp_x; tmpy = (xa_imagey * xa_disp_x) / xa_imagex;}
	else if (xa_disp_y != 0) /* if just y, then adjust x */
		{tmpy = xa_disp_y; tmpx = (xa_imagex * xa_disp_y) / xa_imagey;}
	else
	{
		/* handle any scaling */
	  tmpx = (ULONG)((float)(xa_imagex) * xa_scalex);
	  if (tmpx == 0) tmpx = xa_imagex;
	  tmpy = (ULONG)((float)(xa_imagey) * xa_scaley);
	  if (tmpy == 0) tmpy = xa_imagey;
	}
	/* handle any IFF laced images */
	if ( (xa_allow_lace==TRUE) && (cur_file->anim_flags & ANIM_LACE))
		tmpy >>= 1;
	else	cur_file->anim_flags &= ~ANIM_LACE;
	cur_file->dispx = tmpx;
	cur_file->dispy = tmpy;
	if (tmpx > xa_max_disp_x) xa_max_disp_x = tmpx;
	if (tmpy > xa_max_disp_y) xa_max_disp_y = tmpy;

	if ((cmap_dither_type == CMAP_DITHER_FLOYD) && (xa_buffer_flag==FALSE))
			cur_file->anim_flags |= ANIM_3RD_BUF;
	xa_merged_anim_flags |= cur_file->anim_flags;

	/* NOTE: removed fade, remember to readd eventually */

	if (xa_time_flag == TRUE)
	{
	  LONG time_int;
	  xa_time_end = XA_Time_Read();
	  time_int = xa_time_end - xa_time_start;
	  fprintf(stderr,"time = %ld\n",time_int);
	  xa_time_start = XA_Time_Read();
	}
      } /* valid animation file */
    } /* end of read in file */
 } /* end of loopin through arguments */

 /* No anims listed
  */
 if (first_file == 0) Usage_Quick();

 /* Set up X11 Display
  */

#if XJUNK
 if (xa_noresize_flag==TRUE) X11_Setup_Window(xa_max_disp_x,xa_max_disp_y,
		xa_max_disp_x,xa_max_disp_y);
 else X11_Setup_Window(xa_max_disp_x,xa_max_disp_y,
		first_file->dispx, first_file->dispy);
 if (x11_display_type == XA_MONOCHROME) xa_optimize_flag = FALSE;
 
 /* color map manipulation */
 CMAP_Manipulate_CHDRS();

 /* Kludge for some X11 displays */
 if (x11_kludge_1 == TRUE) CMAP_Expand_Maps();
#endif

 xa_time_start = XA_Time_Read();
 cur_file = first_file;
 while(cur_file)
 {
   ACT_Make_Images(cur_file->acts);
   cur_file = cur_file->next_file;
   if (cur_file == first_file) cur_file = 0;
 }
 if (xa_time_flag == TRUE)
 {
   LONG time_int;
   xa_time_end = XA_Time_Read();
   time_int = xa_time_end - xa_time_start;
   fprintf(stderr,"ACT_Make_Images: time = %ld\n",time_int);
   xa_time_start = XA_Time_Read();
 }

#if XJUNK
 /* Start off Animation.
  */
  ShowAnimation();
 /* Map window and then Wait for user input.
  */
  X11_Map_Window();
  xanim_events();
#else
    debug("Start Animation here ...\n");
    cur_file = first_file;
    while(cur_file)
    {
	debug("Animation %s, file %s\n", cur_file->name, cur_file->fname);
	while (1) {
	    PrintAction();
	    Step_Frame_Next();
	    if (!cur_frame || cur_frame>250) break;
	}
	cur_file = cur_file->next_file;
	if (cur_file == first_file) cur_file = 0;
    }
#endif
 /* Self-Explanatory
  */
  TheEnd();
  return(0);
}


/*
 * ShowAnimation allocates and sets up required image buffers and
 * initializes animation variables.
 * It then kicks off the animation.
 */
void ShowAnimation()
{
  xa_max_image_size = xa_max_imagex * xa_max_imagey;
  xa_max_disp_size = xa_max_disp_x * xa_max_disp_y;
  if (   (xa_merged_anim_flags & ANIM_SNG_BUF)
      || (xa_merged_anim_flags & ANIM_DBL_BUF) )
  {
#ifdef XSHM
    if (shm)
    {
      im0_Image = XShmCreateImage(theDisp,theVisual,x11_depth,
                ZPixmap, 0, &im0_shminfo, xa_max_imagex, xa_max_imagey );
      im0_shminfo.shmid = shmget(IPC_PRIVATE, 
		xa_max_image_size * x11_bytes_pixel, (IPC_CREAT | 0777 ));
      if (im0_shminfo.shmid < 0) { perror("shmget"); exit(0); }
      im0_shminfo.shmaddr = (char *) shmat(im0_shminfo.shmid, 0, 0);
      XSync(theDisp, False);
      x11_error_possible = 1;  /* if remote display. following will fail */
      XShmAttach(theDisp, &im0_shminfo);
      XSync(theDisp, False);
      if (x11_error_possible == -1) /* above failed - back off */
      {
	shm = 0;
	x11_error_possible = 0;
	if (xa_verbose) fprintf(stderr,"SHM Attach failed: backing off\n");
	shmdt(im0_shminfo.shmaddr);     im0_shminfo.shmaddr = 0;
	im0_Image->data = 0;
	XDestroyImage(im0_Image);       im0_Image = 0;
	im_buff0 = (char *) malloc(xa_max_image_size * x11_bytes_pixel);
	if (im_buff0 == 0) TheEnd1("ShowAnimation: im_buff0 malloc err0");
      }
      else
      {
        shmctl(im0_shminfo.shmid, IPC_RMID, 0 );
        im0_Image->data = im_buff0 = im0_shminfo.shmaddr;
        sh_Image = im0_Image;
DEBUG_LEVEL1 fprintf(stderr,"IM_BUFF0 = %lx im0_IMAGE = %lx\n",im_buff0,im0_Image);
      }
    } else
#endif /* XSHM */
    {
      im_buff0 = (char *) malloc(xa_max_image_size * x11_bytes_pixel);
      if (im_buff0 == 0) TheEnd1("ShowAnimation: im_buff0 malloc err0");
    }
    memset(im_buff0,0x00,(xa_max_image_size * x11_bytes_pixel) );  
  }
  if (xa_merged_anim_flags & ANIM_DBL_BUF)
  {
#ifdef XSHM
    if (shm)
    {
      im1_Image = XShmCreateImage(theDisp,theVisual,x11_depth,
                ZPixmap, 0, &im1_shminfo, xa_max_imagex, xa_max_imagey );
      im1_shminfo.shmid = shmget(IPC_PRIVATE, 
		xa_max_image_size * x11_bytes_pixel, (IPC_CREAT | 0777 ));
      if (im1_shminfo.shmid < 0) { perror("shmget"); exit(0); }
      im1_shminfo.shmaddr = (char *) shmat(im1_shminfo.shmid, 0, 0);
      XSync(theDisp, False);
      XShmAttach(theDisp, &im1_shminfo);
      XSync(theDisp, False);
      shmctl(im1_shminfo.shmid, IPC_RMID, 0 );
      im1_Image->data = im_buff1 = im1_shminfo.shmaddr;
DEBUG_LEVEL1 fprintf(stderr,"IM_BUFF1 = %lx im1_IMAGE = %lx\n",im_buff1,im1_Image);
    } else
#endif /* XSHM */
    {
      im_buff1 = (char *) malloc(xa_max_image_size);
      if (im_buff1 == False) TheEnd1("ShowAnimation: im_buff1 malloc err");
    }
  }
  if (xa_merged_anim_flags & ANIM_3RD_BUF)
  {
#ifdef XSHM
    if (shm)
    {
      im2_Image = XShmCreateImage(theDisp,theVisual,x11_depth,
                ZPixmap, 0, &im2_shminfo, xa_max_imagex, xa_max_imagey );
      im2_shminfo.shmid = shmget(IPC_PRIVATE, 
		xa_max_image_size * x11_bytes_pixel, (IPC_CREAT | 0777 ));
      if (im2_shminfo.shmid < 0) { perror("shmget"); exit(0); }
      im2_shminfo.shmaddr = (char *) shmat(im2_shminfo.shmid, 0, 0);
      XSync(theDisp, False);
      XShmAttach(theDisp, &im2_shminfo);
      XSync(theDisp, False);
      shmctl(im2_shminfo.shmid, IPC_RMID, 0 );
      im2_Image->data = im_buff2 = im2_shminfo.shmaddr;
DEBUG_LEVEL2 fprintf(stderr,"IM_BUFF2 = %lx im2_IMAGE = %lx\n",im_buff2,im2_Image);
    } else
#endif /* XSHM */
    {
      im_buff2 = (char *) malloc(xa_max_image_size * x11_bytes_pixel);
      if (im_buff2 == 0) TheEnd1("ShowAnimation: im_buff2 malloc err1");
    }
  }
  if ( (x11_bits_per_pixel == 2) || (x11_bits_per_pixel == 4) )
  {
    ULONG tsize;
    ULONG pbb = (8 / x11_bits_per_pixel);
    tsize = (xa_max_imagex + pbb - 1) / pbb;
    im_buff3 = (char *) malloc(xa_max_disp_y * tsize);
    if (im_buff3 == 0) TheEnd1("ShowAnimation: im_buff3 malloc err1");
    x11_pack_flag = TRUE;
  }
  xa_pic = im_buff0;
  cur_file = first_file;
  cur_floop = 0;
  cur_frame = -1;  /* since we step first */
  file_is_started = FALSE;
  xa_cycle_cnt = 0;
  xa_now_cycling = FALSE;

  xa_anim_ready = TRUE; /* allow expose event to start animation */
}

#if XJUNK
/*
 * This is the heart of this program. It does each action and then calls
 * itself with a timeout via the XtAppAddTimeOut call.
 */
void ShowAction(command,id)
ULONG command;
XtIntervalId *id;
{
 LONG t_frame_start,t_frame_end,t_frame_int;

/* just for benchmarking, currently isn't use */
/*
ShowAction_Loop:
*/

 if (command == XA_SHOW_NORM)
 {
  switch (xa_anim_status)
  {
    case XA_BEGINNING:  
	if (xa_anim_ready == FALSE)
	{ /* try again 10ms later */
	  XtAppAddTimeOut(theContext,10, (XtTimerCallbackProc)ShowAction, 
						(XtPointer)(XA_SHOW_NORM));
	  return;
	}
	xa_anim_status = XA_RUN_NEXT; /* drop through */
    case XA_STEP_NEXT: 
    case XA_RUN_NEXT:   
	Step_Action_Next();
	break;
    case XA_STEP_PREV:
    case XA_RUN_PREV:   
	Step_Action_Prev();
	break;
    case XA_ISTP_NEXT: 
	Step_Frame_Next();
	break;
    case XA_ISTP_PREV: 
	Step_Frame_Prev();
	break;
    case XA_FILE_NEXT:
	Step_File_Next();
	xa_anim_status = XA_STEP_NEXT;
	break;
    case XA_FILE_PREV:
	Step_File_Prev();
	xa_anim_status = XA_STEP_PREV;
	break;
    case XA_UNSTARTED:  
    case XA_STOP_NEXT:  
    case XA_STOP_PREV:  
	if (xa_title_flag != XA_TITLE_NONE)
	{
	  sprintf(xa_title,"XAnim: %s %ld",cur_file->name,cur_frame);
	  XStoreName(theDisp,mainW,xa_title);
	}
	xa_anim_holdoff = FALSE;
	return;
	break;
    default:
	xa_anim_holdoff = FALSE;
	return;
	break;
  }
 }

  DEBUG_LEVEL1 fprintf(stderr,"frame = %ld\n",cur_frame);

 /* 1st throught this particular file.
  * Resize if necessary and init required variables.
  */
  if (file_is_started == FALSE)
  {
     /* If previous anim is still cycling, wait for it to stop */
    if (xa_now_cycling == TRUE)
    {
      xa_anim_flags &= ~(ANIM_CYCLE);
      XtAppAddTimeOut(theContext, 50, (XtTimerCallbackProc)XA_Cycle_Wait, 
							(XtPointer)(NULL) );
      return; 
    }

    file_is_started = TRUE;
    xa_anim_flags = cur_file->anim_flags;
    if (xa_anim_flags & ANIM_PIXMAP) xa_pixmap_flag = TRUE;
    else xa_pixmap_flag = FALSE;

      /* user has not resized window yet */
    if (     (xa_allow_resizing == FALSE)
         || ( (xa_allow_resizing == TRUE) && (x11_window_x==0) )
       )
    {   /* anim if allowed to cause window resizing */
      if (xa_noresize_flag == FALSE)
      {
        if ((xa_disp_x != cur_file->dispx) || (xa_disp_y != cur_file->dispy)) 
        {
DEBUG_LEVEL1 fprintf(stderr,"resizing to <%ld,%ld>\n",cur_file->dispx,cur_file->dispy);
	   XResizeWindow(theDisp,mainW,cur_file->dispx,cur_file->dispy);
	   x11_window_x = cur_file->dispx; x11_window_y = cur_file->dispy;
    	   XSync(theDisp,False);
    	   XFlush(theDisp);
        }
      }
      else /* fixed window size */
      {
        if (xa_disp_x > cur_file->dispx)
		XClearArea(theDisp,mainW,cur_file->dispx,0, 0,0,FALSE);
        if (xa_disp_y > cur_file->dispy)
		XClearArea(theDisp,mainW,0,cur_file->dispy, 0,0,FALSE);
      }
    }
    /* Do Title if set */
    switch(xa_title_flag)
    { 
      case XA_TITLE_FILE:
	sprintf(xa_title,"XAnim: %s",cur_file->name);
	break;
      case XA_TITLE_FRAME:
	if (cur_frame >= 0)
	     sprintf(xa_title,"XAnim: %s %ld",cur_file->name,cur_frame);
	else sprintf(xa_title,"XAnim: %s",cur_file->name);
	break;
      default:
	sprintf(xa_title,"XAnim");
	break;
    }
    XStoreName(theDisp,mainW,xa_title);
    /* Initialize variables
     */
#ifdef XSHM
    if (xa_anim_flags & ANIM_SNG_BUF) sh_Image = im0_Image;
#endif
    if (xa_anim_flags & ANIM_SNG_BUF) xa_pic = im_buff0; 
    xa_imagex = cur_file->imagex;
    xa_imagey = cur_file->imagey;
    xa_disp_x = cur_file->dispx;
    xa_disp_y = cur_file->dispy;
    xa_buff_x = cur_file->buffx;
    xa_buff_y = cur_file->buffy;
    xa_imaged = cur_file->imaged;
    xa_cmap_size = cur_file->imagec;
    xa_image_size = xa_imagex * xa_imagey;
    X11_Init_Image_Struct(theImage,xa_disp_x,xa_disp_y);
    if (xa_anim_flags & ANIM_USE_FILE)
    {
      if (xa_fd>=0) { close(xa_fd); xa_fd = -1; }
      if (xa_codec_buf) { FREE(xa_codec_buf,0x99); xa_codec_buf=0;}
      if ( (xa_fd=open(cur_file->fname,O_RDONLY,NULL)) == 0)
      { 
        fprintf(stderr,"can't open file %s for reading\n",cur_file->fname); 
        TheEnd();
      }
      xa_codec_buf = (char *)malloc( cur_file->max_fsize );
      if (xa_codec_buf==0) TheEnd1("malloc codec_buf err");
    }
    xa_pause_hdr = cur_file->pause_lst; 
    xa_time_start = XA_Time_Read();
  } /* end of file is not started */
 
 /* OK. A quick sanity check and then we act.
  */
 if ( (act = cur_file->frame_lst[cur_frame].act) != 0)
 {
    /* initialize act and get the current time.
     */
    t_frame_start = XA_Time_Read();
    t_frame_int = cur_file->frame_lst[cur_frame].time;

    if ( (xa_allow_resizing == TRUE) && (x11_window_x != 0) )
        { xa_disp_x = x11_window_x; xa_disp_y = x11_window_y; }

    if ((xa_disp_x != xa_buff_x) || (xa_disp_y != xa_buff_y))
	 xa_need_to_scale_b = 1;
    else xa_need_to_scale_b = 0;
    if ((xa_disp_x != xa_imagex) || (xa_disp_y != xa_imagey))
	 xa_need_to_scale_u = 1;
    else xa_need_to_scale_u = 0;

    /* lesdoit */
    switch(act->type)
    {
       /* 
        * NOP and DELAY don't change anything but can have timing info
        * that might prove useful. ie dramatic pauses :^)
        */
     case ACT_NOP:      
                        DEBUG_LEVEL2 fprintf(stderr,"ACT_NOP:\n");
                        break;
     case ACT_DELAY:    
                        DEBUG_LEVEL2 fprintf(stderr,"ACT_DELAY:\n");
                        break;
       /* 
        * Change Color Map.
        */
     case ACT_CMAP:     
        if (   (cmap_play_nice == FALSE) 
	    && (!(x11_display_type & XA_X11_STATIC)) )
	{ ColorReg *tcmap;
	  LONG j;
	  ACT_CMAP_HDR *cmap_hdr;

	  cmap_hdr = (ACT_CMAP_HDR *)act->data;
	  xa_cmap_size = cmap_hdr->csize;
	  if (xa_cmap_size > x11_cmap_size) xa_cmap_size = x11_cmap_size;
	  xa_cmap_off  = cmap_hdr->coff;
	  tcmap      = (ColorReg *)cmap_hdr->data;
	  for(j=0; j<xa_cmap_size;j++)
	  {
		xa_cmap[j].red   = tcmap[j].red;
		xa_cmap[j].green = tcmap[j].green;
		xa_cmap[j].blue  = tcmap[j].blue;
		xa_cmap[j].gray  = tcmap[j].gray;
	  }

/* POD TEMP share routine whith CHDR install */
  if (x11_cmap_flag == TRUE)
  {
    DEBUG_LEVEL2 fprintf(stderr,"CMAP: size=%ld off=%ld\n",
                xa_cmap_size,xa_cmap_off);
    if (x11_display_type & XA_X11_GRAY)
    {
      for(j=0;j<xa_cmap_size;j++)
      {
        defs[j].pixel = xa_cmap_off + j;
        defs[j].red   = xa_cmap[j].gray;
        defs[j].green = xa_cmap[j].gray;
        defs[j].blue  = xa_cmap[j].gray;
        defs[j].flags = DoRed | DoGreen | DoBlue;
      }
    }
    else
    {
      for(j=0; j<xa_cmap_size;j++)
      {
        defs[j].pixel = xa_cmap_off + j;
        defs[j].red   = xa_cmap[j].red;
        defs[j].green = xa_cmap[j].green;
        defs[j].blue  = xa_cmap[j].blue;
        defs[j].flags = DoRed | DoGreen | DoBlue;
        DEBUG_LEVEL3 fprintf(stderr," %ld) %lx %lx %lx <%ld>\n",
          j,xa_cmap[j].red,xa_cmap[j].green,xa_cmap[j].blue,xa_cmap[j].gray);

      }
    }
    XStoreColors(theDisp,theCmap,defs,xa_cmap_size);
    XSync(theDisp,False);
  }

	
	}
	break;
       /* 
        * Lower Color Intensity by 1/16.
        */
     case ACT_FADE:     
                        {
                         LONG j;

                         DEBUG_LEVEL2 fprintf(stderr,"ACT_FADE:\n");
                         if ( (x11_display_type & XA_X11_CMAP) &&
                              (x11_cmap_flag    == TRUE) )
                         {
                           for(j=0;j<xa_cmap_size;j++)
                           {
                             if (xa_cmap[j].red   <= 16) xa_cmap[j].red   = 0;
                             else xa_cmap[j].red   -= 16;
                             if (xa_cmap[j].green <= 16) xa_cmap[j].green = 0;
                             else xa_cmap[j].green -= 16;
                             if (xa_cmap[j].blue  <= 16) xa_cmap[j].blue  = 0;
                             else xa_cmap[j].blue  -= 16;

                             defs[j].pixel = j;
                             defs[j].red   = xa_cmap[j].red   << 8;
                             defs[j].green = xa_cmap[j].green << 8;
                             defs[j].blue  = xa_cmap[j].blue  << 8;
                             defs[j].flags = DoRed | DoGreen | DoBlue;
                           }
                           XStoreColors(theDisp,theCmap,defs,xa_cmap_size);
                           XFlush(theDisp);
                         }
                        }
                        break;
       /* 
        * A IMAGE display only part of an IMAGE.
        */
     case ACT_IMAGE:   
	{
	  Pixmap pix_map = 0;
	  ACT_IMAGE_HDR *act_im_hdr;

	  DEBUG_LEVEL2 fprintf(stderr,"ACT_IMAGE:\n");
	  act_im_hdr = (ACT_IMAGE_HDR *)(act->data);
	  DEBUG_LEVEL2 fprintf(stderr,"  <%ld,%ld> <%ld,%ld>\n",
		act_im_hdr->xpos,  act_im_hdr->ypos,
                act_im_hdr->xsize, act_im_hdr->ysize  );

	  if (xa_need_to_scale_b)
	  {
	    UBYTE *tmp_pic;
	    ULONG xp,yp,xsize,ysize;

	    if(act_im_hdr->clip)
	    {
	      xsize = act_im_hdr->xsize; ysize = act_im_hdr->ysize;
	      xp = act_im_hdr->xpos; yp = act_im_hdr->ypos;
	      tmp_pic = UTIL_Scale_Bitmap(0,act_im_hdr->clip,
		act_im_hdr->xsize,act_im_hdr->ysize,
		(X11_Get_Bitmap_Width(xsize)/8),xa_buff_x,xa_buff_y,
		xa_disp_x,xa_disp_y,&xp,&yp,&xsize,&ysize,
		X11_LSB,X11_LSB);
	      if (tmp_pic)
	      {
                pix_map = XCreatePixmapFromBitmapData(theDisp,mainW,
		 	 (char *)tmp_pic,
		 	 X11_Get_Bitmap_Width(xsize),ysize,0x01,0x00,1);
                XSetClipMask(theDisp,theGC,pix_map);
                XSetClipOrigin(theDisp,theGC,xp,yp);
	      }
	      else pix_map = 0;
	    }

	    xp = act_im_hdr->xpos; yp = act_im_hdr->ypos;
	    if (x11_display_type == XA_MONOCHROME)
	      tmp_pic = UTIL_Scale_Bitmap(0,act_im_hdr->image->data,
		act_im_hdr->xsize,act_im_hdr->ysize,
		act_im_hdr->image->bytes_per_line,xa_buff_x,xa_buff_y,
		xa_disp_x,xa_disp_y,&xp,&yp,&xsize,&ysize,
		x11_bit_order,x11_bit_order);
	    else
	      tmp_pic = UTIL_Scale_Mapped(0,act_im_hdr->image->data,
		   0,0, act_im_hdr->xsize, act_im_hdr->ysize,
		   act_im_hdr->image->bytes_per_line,
		   xa_buff_x,xa_buff_y,xa_disp_x,xa_disp_y,
		   x11_bytes_pixel,&xp,&yp,&xsize,&ysize,0);
	    if (tmp_pic)
	    {
	      theImage->data = (char *)tmp_pic;
		
	      DEBUG_LEVEL1 fprintf(stderr,"IMAGE:scale sz %ldx%ld -> %ldx%ld\n",
		act_im_hdr->xsize,act_im_hdr->ysize,xsize,ysize);
	      DEBUG_LEVEL1 fprintf(stderr,"IMAGE:scale ps %ldx%ld -> %ldx%ld\n",
		act_im_hdr->xpos,act_im_hdr->ypos,xp,yp);
              X11_Init_Image_Struct(theImage,xsize,ysize);
	      if ( (act->chdr != 0) && (act->chdr != xa_chdr_now) )
		XA_Install_CMAP(act->chdr);
	      XPutImage(theDisp,mainW,theGC,theImage,0,0,xp,yp,xsize,ysize);
	    }
	    if(act_im_hdr->clip) XSetClipMask(theDisp,theGC,None);
	  }
	  else /* Not scaling Image */
	  {
            if(act_im_hdr->clip)
            {
              pix_map = XCreatePixmapFromBitmapData(theDisp,mainW,
                (char *)act_im_hdr->clip,
                X11_Get_Bitmap_Width(act_im_hdr->xsize),act_im_hdr->ysize,
                0x01,0x00,1);
              XSetClipMask(theDisp,theGC,pix_map);
              XSetClipOrigin(theDisp,theGC,act_im_hdr->xpos,act_im_hdr->ypos);
            }
	    if ( (act->chdr != 0) && (act->chdr != xa_chdr_now) )
		XA_Install_CMAP(act->chdr);
	    XPutImage(theDisp,mainW,theGC,act_im_hdr->image, 0, 0,
		act_im_hdr->xpos,  act_im_hdr->ypos,
		act_im_hdr->xsize, act_im_hdr->ysize  );
            if (act_im_hdr->clip)
	    {
	      XSetClipMask(theDisp,theGC,None);
              XFreePixmap(theDisp,pix_map);
	    }
	  }
          XSync(theDisp,False);
          if (xa_pixmap_flag == TRUE) XA_Image_To_Pixmap(act);
	}
	break;

       /* 
        * A PIXMAP 
        */
     case ACT_PIXMAP:   
	{
	  ACT_PIXMAP_HDR *act_pm_hdr;

	  DEBUG_LEVEL2 fprintf(stderr,"ACT_PIXMAP:\n");
	  act_pm_hdr = (ACT_PIXMAP_HDR *)(act->data);

          if (xa_need_to_scale_b)
          {
	    Pixmap pix_map;
	    XImage *t_image,*p_image;
	    UBYTE *tmp_pic;
            ULONG xp,yp,xsize,ysize;

	    if (act_pm_hdr->clip)
	    {
	      xp = act_pm_hdr->xpos;      yp = act_pm_hdr->ypos;
	      xsize = act_pm_hdr->xsize;  ysize = act_pm_hdr->ysize;
              p_image = XGetImage(theDisp,act_pm_hdr->clip,0,0,xsize,ysize,
				1,XYPixmap);
              tmp_pic = UTIL_Scale_Bitmap(0,p_image->data,
                xsize,ysize,p_image->bytes_per_line,xa_buff_x,xa_buff_y,
                xa_disp_x,xa_disp_y,&xp,&yp,&xsize,&ysize,
					x11_bit_order,X11_LSB);
              if (tmp_pic)
	      {
                pix_map = XCreatePixmapFromBitmapData(theDisp,mainW,
				(char *)tmp_pic, X11_Get_Bitmap_Width(xsize),
				ysize,0x01,0x00,1);
                XSetClipMask(theDisp,theGC,pix_map);
                XSetClipOrigin(theDisp,theGC,xp,yp);
	      } else pix_map = 0;
	    }

	    xp = act_pm_hdr->xpos;	yp = act_pm_hdr->ypos;
	    xsize = act_pm_hdr->xsize;	ysize = act_pm_hdr->ysize;
            t_image = XGetImage(theDisp,act_pm_hdr->pixmap,0,0,xsize,ysize,
				AllPlanes,ZPixmap);
	    if (x11_display_type == XA_MONOCHROME)
	    {
              t_image = XGetImage(theDisp,act_pm_hdr->pixmap,0,0,xsize,ysize,
				1,XYPixmap);
              tmp_pic = UTIL_Scale_Bitmap(0,t_image->data,
                xsize,ysize,t_image->bytes_per_line,xa_buff_x,xa_buff_y,
                xa_disp_x,xa_disp_y,&xp,&yp,&xsize,&ysize,
					x11_bit_order,x11_bit_order);
	    }
	    else
	    {
              t_image = XGetImage(theDisp,act_pm_hdr->pixmap,0,0,xsize,ysize,
				AllPlanes,ZPixmap);
              tmp_pic = UTIL_Scale_Mapped(0,t_image->data,
                   0,0, xsize, ysize, t_image->bytes_per_line,
                   xa_buff_x,xa_buff_y,xa_disp_x,xa_disp_y,
                   x11_bytes_pixel,&xp,&yp,&xsize,&ysize,0);
	    }
	    if (tmp_pic) /* if image to draw */
	    {
	      theImage->data = (char *)tmp_pic;
	      X11_Init_Image_Struct(theImage,xsize,ysize);
	      if ( (act->chdr != 0) && (act->chdr != xa_chdr_now) )
		  XA_Install_CMAP(act->chdr);
              XPutImage(theDisp,mainW,theGC,theImage,0,0,xp,yp,xsize,ysize);
            }
	    if (act_pm_hdr->clip) 
	    {
	      XSetClipMask(theDisp,theGC,None);
	      XDestroyImage(p_image);
              if (pix_map) XFreePixmap(theDisp,pix_map);
	    }
	    XDestroyImage(t_image);
	    XSync(theDisp,False);
          }
          else /* no rescale */
          {
	    if (act_pm_hdr->clip)
	    {
              XSetClipMask(theDisp,theGC,act_pm_hdr->clip);
              XSetClipOrigin(theDisp,theGC,act_pm_hdr->xpos,act_pm_hdr->ypos);
	      XSetPlaneMask(theDisp,theGC,AllPlanes);
	    }
	    if ( (act->chdr != 0) && (act->chdr != xa_chdr_now) )
		XA_Install_CMAP(act->chdr);
	    XCopyArea(theDisp,act_pm_hdr->pixmap,mainW,theGC, 0, 0, 
		act_pm_hdr->xsize, act_pm_hdr->ysize,
		act_pm_hdr->xpos,  act_pm_hdr->ypos   );
	    XSync(theDisp,False);
	    if (act_pm_hdr->clip) XSetClipMask(theDisp,theGC,None);
          }
	}
	break;

       /* 
        * SETTERS 
        */
     case ACT_IMAGES:
	{
	  ACT_SETTER_HDR *act_ims_hdr;
	  ACT_PIXMAP_HDR *work_pm_hdr;
	  Pixmap work;
	  ACT_IMAGE_HDR *back_im_hdr;
	  XImage *back;
	  LONG xpback,ypback;

	  DEBUG_LEVEL2 fprintf(stderr,"ACT_SETTERS: im\n");
	  act_ims_hdr = (ACT_SETTER_HDR *)(act->data);

	  /* work still needs to be PIXMAP */
          if (act_ims_hdr->work->type != ACT_PIXMAP)
		XA_Image_To_Pixmap(act_ims_hdr->work);
	  work_pm_hdr = (ACT_PIXMAP_HDR *)act_ims_hdr->work->data;
	  work = work_pm_hdr->pixmap;

	  back_im_hdr = (ACT_IMAGE_HDR *)act_ims_hdr->back->data;
	  back = back_im_hdr->image;

	  /* copy backgrnd into work area */
	  DEBUG_LEVEL2 
	    fprintf(stderr,"ACT_SETTERS: back=%lx work=%lx\n",(ULONG)back,work);
	  xpback = act_ims_hdr->xpback;
	  ypback = act_ims_hdr->ypback;
	  DEBUG_LEVEL2 
	    fprintf(stderr,"             bpos = <%ld,%ld>\n",xpback,ypback);
	  {
	    LONG xback,yback;
	    LONG xlen,ylen,xlen1,ylen1;

	    xback = act_ims_hdr->xback;
	    yback = act_ims_hdr->yback;
	    xlen = xback - xpback;
	    ylen = yback - ypback;
	    if (xlen >= xa_buff_x) xlen1 = 0;
	    else xlen1 = xa_buff_x - xlen;
	    if (ylen >= xa_buff_y) ylen1 = 0;
	    else ylen1 = xa_buff_y - ylen;

	    if (xlen1 == 0)
	    { 
	      if (ylen1 == 0)
	      {
		 XPutImage(theDisp, work, theGC, back,
		      xpback,ypback,0,0,xa_buff_x,xa_buff_y );
	      }
	      else
	      {
		 XPutImage(theDisp, work, theGC, back,
		      xpback,ypback,0,   0, xa_buff_x,ylen);
		 XPutImage(theDisp, work, theGC, back,
		      xpback,    0, 0,ylen, xa_buff_x,ylen1);
	      }
	    }
	    else /* xlen1 != 0 */
	    { 
	      if (ylen1 == 0)
	      {
		 XPutImage(theDisp, work, theGC, back,
		      xpback,ypback,0,   0,xlen ,xa_buff_y);
		 XPutImage(theDisp, work, theGC, back,
		          0,ypback,xlen, 0,xlen1,xa_buff_y);
	      }
	      else
	      {
		 XPutImage(theDisp, work, theGC, back,
		      xpback,ypback,    0,    0,  xlen,  ylen);
		 XPutImage(theDisp, work, theGC, back,
		          0,    0, xlen, ylen, xlen1, ylen1);
		 XPutImage(theDisp, work, theGC, back,
		          0,ypback, xlen,    0, xlen1,  ylen);
		 XPutImage(theDisp, work, theGC, back,
		      xpback,    0,    0, ylen,  xlen, ylen1);
	      }
	    }
	  }

	  /* loop through face pixmaps */
	  while(act_ims_hdr != 0)
	  {
	    ACT_IMAGE_HDR *face_im_hdr;
	    Pixmap pix_map = 0;

	    face_im_hdr = (ACT_IMAGE_HDR *)act_ims_hdr->face->data;
	    if (face_im_hdr->clip)
	    {
              pix_map = XCreatePixmapFromBitmapData(theDisp,mainW,
                (char *)face_im_hdr->clip,
                X11_Get_Bitmap_Width(face_im_hdr->xsize),face_im_hdr->ysize,
                0x01,0x00,1);
              XSetClipMask(theDisp,theGC,pix_map);
              XSetClipOrigin(theDisp,theGC,
		act_ims_hdr->xpface,act_ims_hdr->ypface);
            }
	    XPutImage(theDisp, work, theGC,face_im_hdr->image,
		  0, 0, act_ims_hdr->xpface,  act_ims_hdr->ypface,
		        act_ims_hdr->xface, act_ims_hdr->yface    );

            if(face_im_hdr->clip)
            {
              XSetClipMask(theDisp,theGC,None);
              XFreePixmap(theDisp,pix_map);
            }
	    act_ims_hdr = act_ims_hdr->next;
	  }

	  if (xa_need_to_scale_b)
	  {
	    XImage *t_image;
	    ULONG xp,yp,xsize,ysize;
	    UBYTE *tmp_pic;
	    xp = yp = 0; xsize = xa_buff_x; ysize = xa_buff_y;
	    if (x11_display_type == XA_MONOCHROME)
	    {
	      t_image=XGetImage(theDisp,work,0,0,xsize,ysize,1,XYPixmap);
              tmp_pic = UTIL_Scale_Bitmap(0,t_image->data,
                xsize,ysize,t_image->bytes_per_line,xa_buff_x,xa_buff_y,
                xa_disp_x,xa_disp_y,&xp,&yp,&xsize,&ysize,
					x11_bit_order,x11_bit_order);
	    }
	    else
	    {
	      t_image=XGetImage(theDisp,work,0,0,xsize,ysize,AllPlanes,ZPixmap);
              tmp_pic = UTIL_Scale_Mapped(0,t_image->data,
                   0,0, xsize, ysize, t_image->bytes_per_line,
                   xa_buff_x,xa_buff_y,xa_disp_x,xa_disp_y,
                   x11_bytes_pixel,&xp,&yp,&xsize,&ysize,0);
	    }
            if (tmp_pic)
	    {
              theImage->data = (char *)tmp_pic;
              X11_Init_Image_Struct(theImage,xsize,ysize);
              if ( (act->chdr != 0) && (act->chdr != xa_chdr_now) )
                  XA_Install_CMAP(act->chdr);
              XPutImage(theDisp,mainW,theGC,theImage,0,0,xp,yp,xsize,ysize);
	    }
            XDestroyImage(t_image);
	  }
	  else /* not scaling */
	  {
	    if ( (act->chdr != 0) && (act->chdr != xa_chdr_now) )
		XA_Install_CMAP(act->chdr);
	    XCopyArea(theDisp,work,mainW,theGC,0,0,xa_disp_x,xa_disp_y,0, 0);
	  }
	  XSync(theDisp,False);
	}
	break;

       /* 
        * SETTERS 
        */
     case ACT_PIXMAPS:
	{
	  ACT_SETTER_HDR *act_pms_hdr;
	  ACT_PIXMAP_HDR *back_pm_hdr,*work_pm_hdr;
	  Pixmap work,back;
	  LONG xpback,ypback;

	  DEBUG_LEVEL2 fprintf(stderr,"ACT_SETTERS:\n");
	  act_pms_hdr = (ACT_SETTER_HDR *)(act->data);

          if (act_pms_hdr->back->type != ACT_PIXMAP)
		XA_Image_To_Pixmap(act_pms_hdr->back);
          if (act_pms_hdr->work->type != ACT_PIXMAP)
		XA_Image_To_Pixmap(act_pms_hdr->work);
	  back_pm_hdr = (ACT_PIXMAP_HDR *)act_pms_hdr->back->data;
	  work_pm_hdr = (ACT_PIXMAP_HDR *)act_pms_hdr->work->data;
	  back = back_pm_hdr->pixmap;
	  work = work_pm_hdr->pixmap;

	  /* copy backgrnd into work area */
	  DEBUG_LEVEL2 
	    fprintf(stderr,"ACT_SETTERS: back=%lx work=%lx\n",back,work);
	  xpback = act_pms_hdr->xpback;
	  ypback = act_pms_hdr->ypback;
	  DEBUG_LEVEL2 
	    fprintf(stderr,"             bpos = <%ld,%ld>\n",xpback,ypback);
	  {
	    LONG xback,yback;
	    LONG xlen,ylen,xlen1,ylen1;

	    xback = act_pms_hdr->xback;
	    yback = act_pms_hdr->yback;
	    xlen = xback - xpback;
	    ylen = yback - ypback;
	    if (xlen >= xa_buff_x) xlen1 = 0;
	    else xlen1 = xa_buff_x - xlen;
	    if (ylen >= xa_buff_y) ylen1 = 0;
	    else ylen1 = xa_buff_y - ylen;

	    if (xlen1 == 0)
	    { 
	      if (ylen1 == 0)
	      {
	         XCopyArea(theDisp, back, work, theGC,
		      xpback,ypback,xa_buff_x,xa_buff_y,0,0);
	      }
	      else
	      {
	         XCopyArea(theDisp, back, work, theGC,
		      xpback,ypback,xa_buff_x,ylen ,0,   0);
	         XCopyArea(theDisp, back, work, theGC,
		      xpback,    0,xa_buff_x,ylen1,0,ylen);
	      }
	    }
	    else /* xlen1 != 0 */
	    { 
	      if (ylen1 == 0)
	      {
	         XCopyArea(theDisp, back, work, theGC,
		      xpback,ypback,xlen ,xa_buff_y,0,   0);
	         XCopyArea(theDisp, back, work, theGC,
		          0,ypback,xlen1,xa_buff_y,xlen,0);
	      }
	      else
	      {
	         XCopyArea(theDisp, back, work, theGC,
		      xpback,ypback,  xlen,  ylen,    0,    0);
	         XCopyArea(theDisp, back, work, theGC,
		          0,    0, xlen1, ylen1, xlen, ylen);
	         XCopyArea(theDisp, back, work, theGC,
		          0,ypback, xlen1,  ylen, xlen,    0);
	         XCopyArea(theDisp, back, work, theGC,
		      xpback,    0,  xlen, ylen1,    0, ylen);
	      }
	    }
	  }

	  /* loop through face pixmaps */
	  while(act_pms_hdr != 0)
	  {
	    ULONG ret;
	    ACT_PIXMAP_HDR *face_pm_hdr;

            if (act_pms_hdr->face->type != ACT_PIXMAP)
                ret = XA_Image_To_Pixmap(act_pms_hdr->face);
	    face_pm_hdr = (ACT_PIXMAP_HDR *)act_pms_hdr->face->data;
	    if (face_pm_hdr->clip)
	    {
              XSetClipMask(theDisp,theGC,face_pm_hdr->clip);
              XSetClipOrigin(theDisp,theGC,
		act_pms_hdr->xpface,act_pms_hdr->ypface);
	    }

	    XCopyArea(theDisp,
		  face_pm_hdr->pixmap, work, theGC,
		  0, 0, 
		  act_pms_hdr->xface, act_pms_hdr->yface,
		  act_pms_hdr->xpface,  act_pms_hdr->ypface   );
	    if (face_pm_hdr->clip) XSetClipMask(theDisp,theGC,None);
	    act_pms_hdr = act_pms_hdr->next;
	  }

	  if (xa_need_to_scale_b)
	  {
	    XImage *t_image;
	    ULONG xp,yp,xsize,ysize;
	    UBYTE *tmp_pic;
	    xp = yp = 0; xsize = xa_buff_x; ysize = xa_buff_y;
	    if (x11_display_type == XA_MONOCHROME)
	    {
	      t_image=XGetImage(theDisp,work,0,0,xsize,ysize,1,XYPixmap);
              tmp_pic = UTIL_Scale_Bitmap(0,t_image->data,
                xsize,ysize,t_image->bytes_per_line,xa_buff_x,xa_buff_y,
                xa_disp_x,xa_disp_y,&xp,&yp,&xsize,&ysize,
					x11_bit_order,x11_bit_order);
	    }
	    else
	    {
	      t_image=XGetImage(theDisp,work,0,0,xsize,ysize,AllPlanes,ZPixmap);
              tmp_pic = UTIL_Scale_Mapped(0,t_image->data,
                   0,0, xsize, ysize, t_image->bytes_per_line,
                   xa_buff_x,xa_buff_y,xa_disp_x,xa_disp_y,
                   x11_bytes_pixel,&xp,&yp,&xsize,&ysize,0);
	    }
            if (tmp_pic)
	    {
              theImage->data = (char *)tmp_pic;
              X11_Init_Image_Struct(theImage,xsize,ysize);
              if ( (act->chdr != 0) && (act->chdr != xa_chdr_now) )
                  XA_Install_CMAP(act->chdr);
              XPutImage(theDisp,mainW,theGC,theImage,0,0,xp,yp,xsize,ysize);
	    }
            XDestroyImage(t_image);
	  }
	  else
	  {
	    if ( (act->chdr != 0) && (act->chdr != xa_chdr_now) )
		XA_Install_CMAP(act->chdr);
	    XCopyArea(theDisp,work,mainW,theGC,0,0,xa_disp_x,xa_disp_y,0, 0);
	  }
	  XSync(theDisp,False);
	}
	break;

       /* 
        * Act upon IFF Color Cycling chunk.
        */
     case ACT_CYCLE:
{
/* if there is a new_chdr, install it, not the old one */
/*
 XA_CHDR *the_chdr;
if (act->chdr->new_chdr) the_chdr = act->chdr->new_chdr;
else the_chdr = act->chdr;
*/

        if (   (cmap_play_nice == FALSE) 
	    && (x11_display_type & XA_X11_CMAP)
	    && (xa_anim_flags & ANIM_CYCLE) )
	{
	  ACT_CYCLE_HDR *act_cycle;
	  act_cycle = (ACT_CYCLE_HDR *)act->data;

	  DEBUG_LEVEL2 fprintf(stderr,"ACT_CYCLE:\n");
	  if ( !(act_cycle->flags & ACT_CYCLE_STARTED) )
	  {
	      if ( (act->chdr != 0) && (act->chdr != xa_chdr_now) )
			XA_Install_CMAP(act->chdr);
	      xa_cycle_cnt++;
	      act_cycle->flags |= ACT_CYCLE_STARTED;
	      xa_now_cycling = TRUE;
	      XtAppAddTimeOut(theContext,(int)(act_cycle->rate), 
		  (XtTimerCallbackProc)XA_Cycle_It, (XtPointer)(act_cycle));
	  }
	}
} /*POD*/
	break;

     case ACT_DELTA:        
     {
	ACT_DLTA_HDR *dlta_hdr = (ACT_DLTA_HDR *)act->data;
	ULONG xsrc,ysrc,xdst,ydst,xsize,ysize,*remap_map;
	ULONG xbuff,ybuff,map_flag,dith_flag,dlta_flag;
	XA_CHDR *the_chdr;
	char *the_pic;
	ULONG no_shared;

        no_shared = 0;
	if (cmap_dither_type == CMAP_DITHER_FLOYD) dith_flag = TRUE;
	else dith_flag = FALSE; 
	/* if there is a new_chdr, install it, not the old one */
	if (act->chdr->new_chdr) 
	{
	  /* if dithering and new_chdr then don't remap while decoding */
	  if (dith_flag)  map_flag = FALSE;
	  else map_flag = TRUE;
	  the_chdr = act->chdr->new_chdr;
	}
	else 
	{
	  /* remap to larger pixel size NOTE: all anim are 1 byte */
	  if (   (x11_display_type & XA_X11_TRUE)
	      || (x11_kludge_1 == TRUE)
	      || (x11_bytes_pixel != 1)		  ) map_flag = TRUE;
	  else map_flag = FALSE;
	  dith_flag = FALSE;
	  the_chdr = act->chdr;
	}
	remap_map = act->chdr->map;

	the_pic = xa_pic; xbuff = xa_imagex; ybuff = xa_imagey;
	if ((xa_fd >= 0) && (!(dlta_hdr->flags & DLTA_DATA)) )
	{
	  XA_Read_Delta(xa_codec_buf,xa_fd,dlta_hdr->fpos,dlta_hdr->fsize);
	  dlta_flag = dlta_hdr->delta(the_pic,xa_codec_buf,dlta_hdr->fsize,
			act->chdr,remap_map,map_flag,xbuff,ybuff,xa_imaged,
			&xsrc,&ysrc,&xsize,&ysize,dlta_hdr->special,
			dlta_hdr->extra);
	}
	else
	{
	  dlta_flag = dlta_hdr->delta(the_pic,dlta_hdr->data,dlta_hdr->fsize,
			act->chdr,remap_map,map_flag,xbuff,ybuff,xa_imaged,
			&xsrc,&ysrc,&xsize,&ysize,dlta_hdr->special,
			dlta_hdr->extra);
	}
	if (x11_expose_flag == TRUE) { x11_expose_flag = FALSE;
		xsrc = ysrc = 0; xsize = xbuff; ysize = ybuff; }
	else if (dlta_flag & ACT_DLTA_NOP) { act->type = ACT_NOP; break; }

	if (dlta_flag & ACT_DLTA_BODY)
	{
	  if (im_buff0 && (im_buff0 != the_pic) )
		memcpy((char *)im_buff0, (char *)the_pic, xa_image_size);
	  if (im_buff1 && (im_buff1 != the_pic) )
		memcpy((char *)im_buff1, (char *)the_pic, xa_image_size);
	  xsize = dlta_hdr->xsize; ysize = dlta_hdr->ysize;
	  xa_image_size = xa_imagex * xa_imagey;
	  IFF_Init_DLTA_HDR(xsize,ysize);
	}
	if (xa_anim_flags & ANIM_DBL_BUF)
	{
	  IFF_Update_DLTA_HDR(&xsrc,&ysrc,&xsize,&ysize);
	  xa_pic = (xa_pic==im_buff0)?im_buff1:im_buff0;
	} 

	/* convert min/max to pos/size */
	xsize -= xsrc;	ysize -= ysrc;
	xdst = xsrc; ydst = ysrc;
        if (xsize == 0) {act->type = ACT_NOP; fprintf(stderr,"QQ\n"); break;}

        if (xa_anim_flags & ANIM_HAM)
	{
	  xsize =  4*((xsize+3)/4); /* PODTEST */
	  if (xa_anim_flags & ANIM_HAM6) IFF_Buffer_HAM6(im_buff2,the_pic,
		act->chdr,act->h_cmap,xsize,ysize,xsrc,ysrc,xbuff,TRUE);
	  else			 IFF_Buffer_HAM8(im_buff2,the_pic,
		act->chdr,act->h_cmap,xsize,ysize,xsrc,ysrc,xbuff,TRUE);
	  the_pic = im_buff2;
#ifdef XSHM
          if (shm) { sh_Image = im2_Image; }
#endif
	  dlta_flag |= ACT_DLTA_MAPD;
	  xsrc = ysrc = 0; xbuff = xsize; ybuff = ysize;
	}

	if (x11_display_type == XA_MONOCHROME)
	{ no_shared = 1;
	  if (xa_need_to_scale_u)
	  {
	    UBYTE *tmp_pic;
	    ULONG line_size;
		tmp_pic = UTIL_Scale_Mapped(0,the_pic,0,0,
			xbuff,ybuff, xbuff,
			xa_imagex,xa_imagey, xa_disp_x,xa_disp_y,
			x11_bytes_pixel,&xdst,&ydst,&xsize,&ysize,0);
		if (tmp_pic == 0) break; /* NOP */
		line_size = X11_Get_Line_Size(xsize);
		UTIL_Mapped_To_Bitmap(tmp_pic,tmp_pic,act->chdr,0,0,
		    xsize,ysize,xsize,ysize,line_size);
		xsrc = ysrc = 0;
	        theImage->data = (char *)tmp_pic;
	        X11_Init_Image_Struct(theImage,xsize,ysize);
	  } /* end of scale */
	  else
	  {
		ULONG line_size,tsize;
		tsize = ysize * X11_Get_Line_Size(xsize);
		XA_REALLOC(xa_disp_buff,xa_disp_buff_size,tsize);
		line_size = X11_Get_Line_Size(xbuff);
		UTIL_Mapped_To_Bitmap(xa_disp_buff,the_pic,act->chdr,
			xsrc,ysrc,xsize,ysize,xbuff,ybuff,line_size);
		xsrc = ysrc = 0;
	        theImage->data = xa_disp_buff;
	        X11_Init_Image_Struct(theImage,xsize,ysize);
	  }
	} /* end of mono */
        else
        {
	  if (dith_flag == TRUE) /* map here if dithering is on */
	  {
	    if (cmap_dither_type == CMAP_DITHER_FLOYD)
	    {
	      UTIL_Mapped_To_Floyd(im_buff2,the_pic,
	      		act->chdr->new_chdr,act->chdr,xsrc,ysrc,
			xsize,ysize,xbuff,ybuff);
		xsrc = ysrc = 0; xbuff = xsize; ybuff = ysize;
		the_pic = im_buff2;	dlta_flag |= ACT_DLTA_MAPD;
#ifdef XSHM
		if (shm) 
		{ sh_Image = im2_Image; 
	          X11_Init_Image_Struct(im2_Image,xbuff,ybuff);
		}
#endif
	    }
	  } /* end of dither */

	  if (xa_need_to_scale_u)
	  {
	    XA_CHDR *tmp_chdr;
	    UBYTE *tmp_pic;
	    no_shared = 1;
	    if ((map_flag==TRUE) && (!(dlta_flag & ACT_DLTA_MAPD)) )
				tmp_chdr = the_chdr;
	    else tmp_chdr = 0;
	    tmp_pic = UTIL_Scale_Mapped(0,the_pic,xsrc,ysrc,
			  xsize,ysize,X11_Get_Line_Size(xbuff),
			  xa_imagex,xa_imagey,xa_disp_x,xa_disp_y,
			  x11_bytes_pixel,&xdst,&ydst,&xsize,&ysize,tmp_chdr);
            if (tmp_pic==0) break; /*NOP*/
            xsrc = ysrc = 0;
	    theImage->data = (char *)tmp_pic;
	    xbuff = xsize; ybuff = ysize;
	  } /* end of scaling */
	  else /* no scaling */
	  {
	    if (   ((x11_bytes_pixel > 1) && (!(dlta_flag & ACT_DLTA_MAPD)))
	        || ((map_flag==TRUE) && (!(dlta_flag & ACT_DLTA_MAPD)))     )
	    {
		ULONG tsize = (xsize) * (ysize) * x11_bytes_pixel;
		XA_REALLOC(xa_disp_buff,xa_disp_buff_size,tsize);
		UTIL_Mapped_To_Mapped(xa_disp_buff,the_pic,act->chdr,
			xsrc,ysrc,xsize,ysize,xbuff,ybuff);
		xsrc = ysrc = 0;
		theImage->data = (char *)xa_disp_buff;
		xbuff = xsize; ybuff = ysize;
	        no_shared = 1;
	    } 
	    else 
	    { 
#ifdef XSHM
	      if (shm) sh_Image->data = the_pic;
#endif
	      theImage->data = the_pic;
	    }
	  } /* end of no scaling */

          if (x11_pack_flag == TRUE)
	  { no_shared = 1;
	    UTIL_Pack_Image(im_buff3,theImage->data,xbuff,ybuff);
	    theImage->data = im_buff3;
	  }
#ifdef XSHM
	  if (sh_Image) X11_Init_Image_Struct(sh_Image,xbuff,ybuff);
#endif
	  X11_Init_Image_Struct(theImage,xbuff,ybuff);
        } /* end of not mono */

	if (xa_no_disp == FALSE)
	{
	  if ( (the_chdr != 0) && (the_chdr != xa_chdr_now) )
						XA_Install_CMAP(the_chdr);
#ifdef XSHM
	if (shm && (no_shared==0) )
	{
DEBUG_LEVEL1  fprintf(stderr,"sh_IMAGE = %lx sh_image->data = %lx \n",sh_Image,sh_Image->data);
DEBUG_LEVEL1  fprintf(stderr,"     from <%ld,%ld> to <%ld,%ld> <%ld,%ld>\n",xsrc,ysrc,xdst,ydst,xsize,ysize);
            XSync(theDisp, False);
	    XShmPutImage(theDisp,mainW,theGC,sh_Image,
				xsrc,ysrc,xdst,ydst,xsize,ysize,True );
	} else
#endif
          {
	    XPutImage(theDisp,mainW,theGC,theImage,
				xsrc,ysrc,xdst,ydst,xsize,ysize );
          }
	  XSync(theDisp,False);
	}
#ifdef XSHM
	if ( (shm) && (xa_anim_flags & ANIM_DBL_BUF) ) 
          {sh_Image = (xa_pic==im_buff0)?im0_Image:im1_Image;}
        /* note: xa_pic already swapped */
#endif
      } /* end of DELTA case */
      break;

     default:           
                        fprintf(stderr,"Unknown not supported %lx\n",act->type);
    } /* end of switch of action type */
 } /* end of action valid */

 if (xa_pause_hdr)
 {
   if (cur_frame==xa_pause_hdr->frame)
   {
     xa_pause_hdr = xa_pause_hdr->next;
     goto XA_PAUSE_ENTRY_POINT;
   }
 }


 if (xa_anim_status & XA_STEP_MASK) /* Single step if in that mode */
 {
   XA_PAUSE_ENTRY_POINT:
   if ( (xa_no_disp == FALSE) & (xa_title_flag != XA_TITLE_NONE) )
   {
     sprintf(xa_title,"XAnim: %s %ld",cur_file->name,cur_frame);
     XStoreName(theDisp,mainW,xa_title);
   }
   xa_anim_status &= XA_CLEAR_MASK; /* preserve direction and stop */
   xa_anim_status |= XA_STOP_MASK;
   xa_anim_holdoff = FALSE;
   return;
 }

 if ( (xa_no_disp == FALSE) & (xa_title_flag == XA_TITLE_FRAME) )
 {
   sprintf(xa_title,"XAnim: %s %ld",cur_file->name,cur_frame);
   XStoreName(theDisp,mainW,xa_title);
 }
  /* Harry, what time is it? and how much left? default to 1 ms */
 t_frame_end = XA_Time_Read() - t_frame_start;
 t_frame_end = t_frame_int - t_frame_end;
 if (t_frame_end <=0 ) t_frame_end = 1; 
 t_frame_end = (xa_speed_scale * t_frame_end) >> 16; 
 if (t_frame_end <=0 ) t_frame_end = 1;
 /* if ran out of time, jump back real quick */
/* was just benchmarking
 if ( (t_frame_end <= 0) && !(xa_anim_status & XA_STOP_MASK) )
 {
   command == XA_SHOW_NORM;
   goto ShowAction_Loop;
 }
*/
 
 if ( !(xa_anim_status & XA_STOP_MASK) )
   XtAppAddTimeOut(theContext,t_frame_end,(XtTimerCallbackProc)ShowAction,
						(XtPointer)(XA_SHOW_NORM));
 else xa_anim_holdoff = FALSE;
}
#endif
/*
 *
 */
void Step_Action_Next()
{
  XA_FRAME *frame;

  cur_frame++; frame = &cur_file->frame_lst[cur_frame];
  do
  { ULONG jmp2end_flag = 0;
    if ( (frame->time == 0) && (frame->act != 0) ) /* check for loops */
    {
      XA_ACTION *lp_act = frame->act;
      if (lp_act->type == ACT_BEG_LP)
      {
        ACT_BEG_LP_HDR *beg_lp = (ACT_BEG_LP_HDR *)lp_act->data;
        beg_lp->cnt_var = beg_lp->count;
        cur_frame++; /* move on */
      }
      else if (lp_act->type == ACT_END_LP)
      {
        ACT_END_LP_HDR *end_lp = (ACT_END_LP_HDR *)lp_act->data;
        *end_lp->cnt_var = *end_lp->cnt_var - 1;
        if (*end_lp->cnt_var > 0) cur_frame = end_lp->begin_frame;
        else cur_frame++;
      }
      else if (lp_act->type == ACT_JMP2END)
      { 
	if (xa_pingpong_flag==FALSE)
	{
	  if (   ((cur_floop+1) >= cur_file->loop_num)
              && (first_file->next_file != first_file)
	     )
		cur_frame = cur_file->last_frame + 1; /* jmp to end */
	  else	cur_frame++;
        } else jmp2end_flag = 1;
      }
      frame = &cur_file->frame_lst[cur_frame];
    }

    if ( (frame->act == 0) /* Are we at the end of an anim? */
        || (jmp2end_flag) )
    {
      if (xa_pingpong_flag == TRUE)
      { jmp2end_flag = 0;
        xa_anim_status &= ~(XA_NEXT_MASK);  /* change dir to prev */
        cur_frame--; 
        Step_Action_Prev();
        return;
      }
      cur_frame = cur_file->loop_frame;

      cur_floop++;
      DEBUG_LEVEL1 fprintf(stderr,"  loop = %ld\n",cur_floop);

      /* Done looping animation. Move on to next file if present */
      if (   (cur_floop >= cur_file->loop_num)
	  || (xa_anim_status & XA_STEP_MASK)   ) /* or if single stepping */
      {
        cur_floop = 0;             /* Reset Loop Count */

	/* Are we on the last file and do we need to exit? */
	if (   (cur_file->next_file == first_file)
	    && (xa_exit_flag == TRUE) )   TheEnd(); /* later */

        /* This is a special case check.
         * If more that one file, reset file_is_started, otherwise
         * if we're only displaying 1 animation jump to the loop_frame
         * which has already been set up above.
         */
        if (first_file->next_file != first_file)
        {
          file_is_started = FALSE;
          cur_file = cur_file->next_file;
          cur_frame = 0;
        }
        DEBUG_LEVEL1 fprintf(stderr,"  file = %ld\n",cur_file->file_num);
        if (xa_time_flag == TRUE) XA_Time_Check();
      } /* end done looping file */
    } /* end done with frames in file */
    frame = &cur_file->frame_lst[cur_frame];
  } while( (frame->time == 0) || (frame->act == 0) );
}

/*
 *
 */
void Step_Action_Prev()
{
  XA_FRAME *frame;
  cur_frame--; if (cur_frame < 0) goto XA_Step_Action_Prev_0;
  frame = &cur_file->frame_lst[cur_frame];

  do
  {
    if ( (frame->time == 0) && (frame->act != 0) ) /* check for loops */
    {
      XA_ACTION *lp_act = frame->act;
      if (lp_act->type == ACT_BEG_LP)
      {
        ACT_BEG_LP_HDR *beg_lp = (ACT_BEG_LP_HDR *)lp_act->data;
        beg_lp->cnt_var++;
        if (beg_lp->cnt_var < beg_lp->count) cur_frame = beg_lp->end_frame;
        else cur_frame--;
      }
      else if (lp_act->type == ACT_END_LP)
      {
        ACT_END_LP_HDR *end_lp = (ACT_END_LP_HDR *)lp_act->data;
        *end_lp->cnt_var = 0;
        cur_frame--;
      }
      else if (lp_act->type == ACT_JMP2END)
      { /* not valid in this direction so just skip over it */
        cur_frame--;
      }
      if (cur_frame < 0) goto XA_Step_Action_Prev_0;
      frame = &cur_file->frame_lst[cur_frame];
    }

    /* Are we at the beginning of an anim? */
    if (cur_frame < 0) goto XA_Step_Action_Prev_0;
    if (   (frame->act == 0) || (cur_frame < cur_file->loop_frame)
       )
    {
      XA_Step_Action_Prev_0:  /* skip indexing with -1 */

      if (xa_pingpong_flag == TRUE)
      {
        xa_anim_status |= XA_NEXT_MASK;  /* change dir to forward */
        cur_floop++;

	/* Are we on the last file and do we need to exit? */
	if (   (cur_file->next_file == first_file)
	    && (xa_exit_flag == TRUE) )   TheEnd(); /* later */

         /* do we move to next file? */
        if (  (first_file->next_file != first_file)  /* more than 1 file */
	    && (   (cur_floop >= cur_file->loop_num)
                || (xa_anim_status & XA_STEP_MASK)  ) )
        {
          cur_floop = 0;
          file_is_started = FALSE;
          cur_file = cur_file->next_file;
          cur_frame = 0;
          break;
        }

        if (cur_floop >= cur_file->loop_num) 
        {
          cur_floop = 0;
          if (xa_time_flag == TRUE) XA_Time_Check();
        }
        cur_frame++;
        Step_Action_Next();
        return;
      } /* end of pingpong stuff */

      cur_frame = cur_file->last_frame;
      cur_floop--;
      DEBUG_LEVEL1 fprintf(stderr,"  loop = %ld\n",cur_floop);
       /* Done looping animation. Move on to next file if present */
      if (   (cur_floop <= 0)
	  || (xa_anim_status & XA_STEP_MASK) ) /* or if single stepping */
      {
        cur_floop = cur_file->loop_num; /* Reset Loop Count */
 
        /* If more that one file, go to next file */
        if (first_file->next_file != first_file )
        {
          file_is_started = FALSE;
          cur_file = cur_file->prev_file;
          cur_frame = cur_file->last_frame;
          cur_floop = cur_file->loop_num; /* Reset Loop Count */
        }

        if (xa_time_flag == TRUE) XA_Time_Check();
        DEBUG_LEVEL1 fprintf(stderr,"  file = %ld\n",cur_file->file_num);
      } /* end done looping file */
    } /* end done with frames in file */
    frame = &cur_file->frame_lst[cur_frame];
  } while( (frame->time == 0) || (frame->act == 0) );
}


/*
 *
 */
void Step_Frame_Next()
{
  cur_frame++;
  do
  {
      /* skip over loops */
    if (   (cur_file->frame_lst[cur_frame].time == 0)
        && (cur_file->frame_lst[cur_frame].act != 0) ) cur_frame++;

      /* Are we at the end of an anim? */
    if (cur_file->frame_lst[cur_frame].act == 0)
    {
      cur_frame = cur_file->loop_frame;
    }
  } while(   (cur_file->frame_lst[cur_frame].time == 0)
          || (cur_file->frame_lst[cur_frame].act == 0)  );
}

/*
 *
 */
void Step_Frame_Prev()
{
  cur_frame--;

  do
  {
      /* skip over loops */
    if (cur_frame < 0) goto XA_Step_Frame_Prev_0;
    if (   (cur_file->frame_lst[cur_frame].time == 0)
        && (cur_file->frame_lst[cur_frame].act != 0) ) cur_frame--;

    /* Are we at the beginning of an anim? */
    if (cur_frame < 0) goto XA_Step_Frame_Prev_0;
    if (   (cur_file->frame_lst[cur_frame].act == 0)
        || (cur_frame < cur_file->loop_frame)        )
    {
      XA_Step_Frame_Prev_0: /* prevent indexing with -1 */
      cur_frame = cur_file->last_frame;
    }
  } while(   (cur_file->frame_lst[cur_frame].time == 0)
          || (cur_file->frame_lst[cur_frame].act == 0)  );
}

/*
 *
 */
void Step_File_Next()
{
  file_is_started = FALSE;
  cur_frame = 0;
  cur_file = cur_file->next_file;
  cur_floop = 0; /* used if things start up again */

  DEBUG_LEVEL1 fprintf(stderr,"  file = %ld\n",cur_file->file_num);
}

/*
 *
 */
void Step_File_Prev()
{
  file_is_started = FALSE;
  cur_frame = 0;
  cur_file = cur_file->prev_file;
  cur_floop = 0; /* used if things start up again */

  DEBUG_LEVEL1 fprintf(stderr,"  file = %ld\n",cur_file->file_num);
}


/*
 * Simple routine to find out the file type. Defaults to FLI.
 */
LONG Determine_Anim_Type(filename)
char *filename;
{ LONG ret;
 if ( Is_RLE_File(filename)==TRUE)	return(RLE_ANIM);
/* if ( Is_SET_File(filename)==TRUE)	return(SET_ANIM); */
 if ( Is_IFF_File(filename)==TRUE)	return(IFF_ANIM); 
 if ( Is_GIF_File(filename)==TRUE)	return(GIF_ANIM); 
 if ( Is_TXT_File(filename)==TRUE)	return(TXT_ANIM); 
 if ( Is_FLI_File(filename)==TRUE)	return(FLI_ANIM); 
 if ( Is_PFX_File(filename)==TRUE)	return(PFX_ANIM);
 if ( Is_AVI_File(filename)==TRUE)	return(AVI_ANIM); 
 if ( (ret=Is_QT_File(filename))==TRUE) return(QT_ANIM);
 if (ret == XA_NOFILE)			return(NOFILE_ANIM);
 if ( Is_DL_File(filename)==TRUE)	return(DL_ANIM);
 return(UNKNOWN_ANIM);
}

#if XJUNK
/*
 *
 */
void XA_Cycle_Wait(nothing, id)
char *nothing;
XtIntervalId *id;
{

  if (xa_cycle_cnt) /* wait until cycles are done */
  {
    XtAppAddTimeOut(theContext, 50, (XtTimerCallbackProc)XA_Cycle_Wait,
							(XtPointer)(NULL));
    return;
  }
  else /* then move on */
  {
    xa_now_cycling = FALSE;
    XtAppAddTimeOut(theContext, 1, (XtTimerCallbackProc)ShowAction, 
						(XtPointer)(XA_SHOW_SKIP));
  }
}

/*
 *
 */
void XA_Cycle_It(act_cycle, id)
ACT_CYCLE_HDR   *act_cycle;
XtIntervalId *id;
{
  ULONG i,*i_ptr,size,curpos;

  if (xa_anim_flags & ANIM_CYCLE) XtAppAddTimeOut(theContext,
		(int)(act_cycle->rate),(XtTimerCallbackProc)XA_Cycle_It,
						(XtPointer)(act_cycle));
  else
  {
    xa_cycle_cnt--;
    act_cycle->flags &= ~ACT_CYCLE_STARTED;
    return;
  }

  size = act_cycle->size;
  curpos = act_cycle->curpos;

  /* increment or decrement curpos */
  if (act_cycle->flags & ACT_CYCLE_REVERSE) 
      curpos = (curpos)?(curpos - 1):(size - 1); 
  else
      curpos = (curpos >= (size - 1))?(0):(curpos + 1); 
  act_cycle->curpos = curpos;

  i_ptr = (ULONG *)act_cycle->data;
  for(i=0;i<size;i++)
  {
    ULONG j;

    j = i_ptr[i] - xa_cmap_off;
    defs[i].pixel = i_ptr[curpos];
    defs[i].flags = DoRed | DoGreen | DoBlue;
    if (x11_display_type & XA_X11_GRAY)
    {
      defs[i].red = defs[i].green = defs[i].blue = xa_cmap[j].gray;
    }
    else
    {
      defs[i].red   = xa_cmap[j].red;
      defs[i].green = xa_cmap[j].green;
      defs[i].blue  = xa_cmap[j].blue;
    }
    if (act_cycle->flags & ACT_CYCLE_REVERSE) 
      curpos = (curpos)?(curpos - 1):(size - 1); 
    else
      curpos = (curpos >= (size - 1))?(0):(curpos + 1); 
  }
  XStoreColors(theDisp,theCmap,defs,act_cycle->size);
  XSync(theDisp,False);
}

#endif
/*
 *
 */
void Free_Actions(acts)
XA_ACTION *acts;
{
  XA_ACTION *act;
  act = acts;
  while(act != 0)
  {
    ACT_Free_Act(act);
    act = act->next;
  }
}

XA_ANIM_HDR *Return_Anim_Hdr(file_hdr)
XA_ANIM_HDR *file_hdr;
{
  XA_ANIM_HDR *tmp_hdr;
  if ((file_hdr==0) || (first_file==0)) TheEnd1("Return_Anim_Hdr err");
  xa_file_num--;
  if (first_file == file_hdr)
  {
    first_file = 0;
    tmp_hdr = 0;
  }
  else /* removed file_hdr from the loop */
  {
    tmp_hdr = file_hdr->prev_file;
    tmp_hdr->next_file = file_hdr->next_file;
    file_hdr->next_file->prev_file = tmp_hdr;
  }
  FREE(file_hdr,0x01);
  return(tmp_hdr);
}

XA_ANIM_HDR *Get_Anim_Hdr(file_hdr,file_name)
XA_ANIM_HDR *file_hdr;
char *file_name;
{
  XA_ANIM_HDR *temp_hdr;
  LONG length;

  temp_hdr = (XA_ANIM_HDR *)malloc( sizeof(XA_ANIM_HDR) );
  if (temp_hdr == 0) TheEnd1("Get_Anim_Hdr: malloc failed\n");

  if (first_file == 0) first_file = temp_hdr;
  if (file_hdr == 0)
  {
    xa_file_num = 0;
    temp_hdr->next_file = temp_hdr;
    temp_hdr->prev_file = temp_hdr;
  }
  else
  {
    temp_hdr->prev_file = file_hdr;
    temp_hdr->next_file = file_hdr->next_file;
    file_hdr->next_file = temp_hdr;
    first_file->prev_file = temp_hdr;
  }

  temp_hdr->anim_type = 0;
  temp_hdr->imagex = 0;
  temp_hdr->imagey = 0;
  temp_hdr->imagec = 0;
  temp_hdr->imaged = 0;
  temp_hdr->anim_flags	= 0;
  temp_hdr->loop_num	= 0;
  temp_hdr->loop_frame	= 0;
  temp_hdr->last_frame	= 0;
  temp_hdr->frame_lst	= 0;
  temp_hdr->acts	= 0;
  temp_hdr->file_num	= xa_file_num;
  temp_hdr->fname	= 0;
  temp_hdr->max_fsize	= 0;
  xa_file_num++;

  length = strlen(file_name);
  temp_hdr->name = (char *)malloc(length + 1);
  strcpy(temp_hdr->name,file_name);
  return(temp_hdr);
}
  
#if XJUNK

void XA_Install_CMAP(chdr)
XA_CHDR *chdr;
{ ColorReg *tcmap;
  LONG j;

  tcmap		= chdr->cmap;
  xa_cmap_size	= chdr->csize;
  if (xa_cmap_size > x11_cmap_size) xa_cmap_size = x11_cmap_size;
  xa_cmap_off	= chdr->coff;
  xa_map	= chdr->map;
  xa_map_size	= chdr->msize;
  xa_map_off	= chdr->moff;
  for(j=0; j<xa_cmap_size;j++)
  {
    xa_cmap[j].red   = tcmap[j].red;
    xa_cmap[j].green = tcmap[j].green;
    xa_cmap[j].blue  = tcmap[j].blue;
    xa_cmap[j].gray  = tcmap[j].gray;
  }

  DEBUG_LEVEL1 fprintf(stderr,"  Install CMAP %lx old was %lx\n",
					(ULONG)chdr,(ULONG)xa_chdr_now);

  if ( x11_cmap_flag == FALSE )
  {
    DEBUG_LEVEL1 fprintf(stderr,"  Fake Install since cmap not writable\n");
    xa_chdr_now = chdr;
    return;
  }
  else /* install the cmap */
  {
    DEBUG_LEVEL2 fprintf(stderr,"CMAP: size=%ld off=%ld\n",
		xa_cmap_size,xa_cmap_off);
    if (xa_cmap_size > x11_cmap_size)
    {
      fprintf(stderr,"Install CMAP: Error csize(%ld) > x11 cmap(%ld)\n",
		xa_cmap_size,x11_cmap_size);
      return;
    }
    if (x11_display_type & XA_X11_GRAY)
    {
      for(j=0;j<xa_cmap_size;j++)
      {
        defs[j].pixel = xa_cmap_off + j;
        defs[j].red   = xa_cmap[j].gray;
        defs[j].green = xa_cmap[j].gray;
        defs[j].blue  = xa_cmap[j].gray;
        defs[j].flags = DoRed | DoGreen | DoBlue;
        DEBUG_LEVEL3 fprintf(stderr," g %ld) %lx %lx %lx <%lx>\n",
             j,xa_cmap[j].red,xa_cmap[j].green,xa_cmap[j].blue,xa_cmap[j].gray);
		
      }
    }
    else
    {
      for(j=0; j<xa_cmap_size;j++)
      {
        defs[j].pixel = xa_cmap_off + j;
        defs[j].red   = xa_cmap[j].red;
        defs[j].green = xa_cmap[j].green;
        defs[j].blue  = xa_cmap[j].blue;
        defs[j].flags = DoRed | DoGreen | DoBlue;
        DEBUG_LEVEL3 fprintf(stderr," %ld) %lx %lx %lx <%lx>\n",
             j,xa_cmap[j].red,xa_cmap[j].green,xa_cmap[j].blue,xa_cmap[j].gray);
		
      }
    }
    XStoreColors(theDisp,theCmap,defs,xa_cmap_size);
    /* XSync(theDisp,False); */
    /* following is a kludge to force the cmap to be loaded each time 
     * this sometimes helps synchronize image to vertical refresh on
     * machines that wait until vertical refresh to load colormap
     */
    if (cmap_force_load == FALSE) xa_chdr_now = chdr;
  }
}
#endif

void XA_Time_Init()
{
  gettimeofday(&tv, 0);
  xa_time_off = tv.tv_sec;
}

/*
 * return time from start in milliseconds
 */
LONG XA_Time_Read()
{
  LONG t;
  gettimeofday(&tv, 0);
  t = (tv.tv_sec - xa_time_off) * 1000 + (tv.tv_usec / 1000);
  return(t);
}


/*
 *
 */
void XA_Time_Check()
{
  LONG time_int;

  xa_time_end = XA_Time_Read();
  time_int = xa_time_end - xa_time_start;
  xa_time_av = (xa_time_av * xa_time_num) + time_int;
  xa_time_num++;
  xa_time_av /= xa_time_num;
  fprintf(stderr,"l_time = %ld  av %ld\n",time_int,xa_time_av);
  xa_time_start = XA_Time_Read();

}

ULONG
XA_Image_To_Pixmap(act)
XA_ACTION *act;
{
  ACT_IMAGE_HDR *act_im_hdr;
  ACT_PIXMAP_HDR *act_pm_hdr;
  ULONG line_size;

  if (act->type == ACT_NOP) return(0);
  if (act->type != ACT_IMAGE) 
  { 
    fprintf(stderr,"XA_Image_To_Pixmap: not Image err %lx\n",act->type);
    TheEnd();
  }
  act_im_hdr = (ACT_IMAGE_HDR *)(act->data);
  act_pm_hdr = (ACT_PIXMAP_HDR *) malloc( sizeof(ACT_PIXMAP_HDR) );
  if (act_pm_hdr == 0) TheEnd1("Image_to_Pixmap: malloc err\n");

  if (x11_display_type == XA_MONOCHROME)
	line_size = X11_Get_Bitmap_Width(act_im_hdr->xsize);
  else line_size = act_im_hdr->xsize;

  if(act_im_hdr->clip)
  {
    act_pm_hdr->clip = 
	XCreatePixmapFromBitmapData(theDisp,mainW,
                (char *)act_im_hdr->clip,
                X11_Get_Bitmap_Width(act_im_hdr->xsize),act_im_hdr->ysize,
                0x01,0x00,1);
    XSync(theDisp,False);
  }
  else act_pm_hdr->clip = 0;

  act->type = ACT_PIXMAP;
  act->data = (UBYTE *) act_pm_hdr;
  act_pm_hdr->xpos  = act_im_hdr->xpos;
  act_pm_hdr->ypos  = act_im_hdr->ypos;
  act_pm_hdr->xsize = act_im_hdr->xsize;
  act_pm_hdr->ysize = act_im_hdr->ysize;
  act_pm_hdr->pixmap = XCreatePixmap(theDisp,mainW,
                line_size, act_pm_hdr->ysize, x11_depth);
  XSync(theDisp,False);
  DEBUG_LEVEL2 fprintf(stderr,
	"XA_Image_To_Pixmap: pixmap = %lx\n", act_pm_hdr->pixmap);
  XSetClipMask(theDisp,theGC,None);
  XPutImage(theDisp, act_pm_hdr->pixmap, theGC, act_im_hdr->image,
      0,0,0,0,act_pm_hdr->xsize,act_pm_hdr->ysize);
  XSync(theDisp,False);
  if (act_im_hdr->clip) { FREE(act_im_hdr->clip,0x01); act_im_hdr->clip=0;}
  XDestroyImage(act_im_hdr->image);
  FREE(act_im_hdr,0x01);
  return(1);
}

ULONG XA_Read_Int(s,j)
UBYTE *s;
ULONG *j;
{
  ULONG i,num;
  i = *j; num = 0;
  while( (s[i] >= '0') && (s[i] <= '9') )
	{ num *= 10; num += (ULONG)(s[i]) - (ULONG)('0'); i++; }
  *j = i;   
  return(num);
}

float XA_Read_Float(s,j)
UBYTE *s;
ULONG *j;
{
  ULONG i;
  float num;
  i = *j; num = 0.0;
  while( (s[i] >= '0') && (s[i] <= '9') )
	{ num *= 10; num += (float)(s[i]) - (float)('0'); i++; }
  if (s[i] == '.')
  {
    float pos = 10.0;
    i++; 
    while( (s[i] >= '0') && (s[i] <= '9') )
    { 
      num += ((float)(s[i]) - (float)('0')) / pos;
      pos *= 10.0; i++;
    }
  }
  *j = i;   
  return(num);
}

LONG XA_Get_Class(p)
char *p;
{
  ULONG i,len;
  char tmp[16];
  
  /* copy and convert to lower case */
  len = strlen(p); if (len > 16) return( -1 );
  for(i=0; i < len; i++) tmp[i] = (char)tolower( (int)(p[i]) );
  tmp[i] = 0;
  if      (strcmp(tmp,"staticgray\0" ) == 0)	return( StaticGray );
  else if (strcmp(tmp,"grayscale\0"  ) == 0)	return( GrayScale );
  else if (strcmp(tmp,"staticcolor\0") == 0)	return( StaticColor );
  else if (strcmp(tmp,"pseudocolor\0") == 0)	return( PseudoColor );
  else if (strcmp(tmp,"truecolor\0"  ) == 0)	return( TrueColor );
  else if (strcmp(tmp,"directcolor\0") == 0)	return( DirectColor );
  else return( -1 );
}

void XA_Read_Delta(dptr,fd,fpos,fsize)
char *dptr;
int fd;
ULONG fpos,fsize;
{
  LONG ret;
  ret = lseek(fd,fpos,SEEK_SET);
  if (ret != fpos) TheEnd1("XA_Read_Delta: Can't seek fpos");
  ret = read(fd,dptr,fsize);
  if (ret != fsize) TheEnd1("XA_Read_Delta: Can't read data");
}

/**********************
 * Add frame to current pause list
 */
void XA_Add_Pause(frame)
ULONG frame;            /* frame at which to pause */
{ XA_PAUSE *new_phdr;

  new_phdr = (XA_PAUSE *)malloc(sizeof(XA_PAUSE));
  if (new_phdr==0) TheEnd1("XA_Add_Pause: malloc err\n");
  new_phdr->frame = frame;
  new_phdr->next = 0;
  if (xa_pause_hdr==0) xa_pause_hdr = new_phdr;
  else
  { XA_PAUSE *t_phdr = xa_pause_hdr;
    while(t_phdr->next != 0) t_phdr = t_phdr->next;
    t_phdr->next = new_phdr;
  }
}

/* NEW CODE GOES HERE */

void PrintDelta(ACT_DLTA_HDR *d)
{
    ULONG xs, ys, xe, ye;
    NXBitmapImageRep *bm;
    NXStream *s;
    int i, fd;
    
    debug("Delta %ld %ld %ld %ld flags=%lx special=%lx extra=%lx fpos=%ld fsize=%ld\n",
	d->xpos, d->ypos, d->xsize, d->ysize, d->flags, d->special, d->extra, d->fpos, d->fsize);
    bm = [[NXBitmapImageRep alloc] initData:NULL
	pixelsWide:d->xsize
	pixelsHigh:d->ysize
	bitsPerSample:8
	samplesPerPixel:3	// (cSpace == RGB_COLOR) ? 3 : 1
	hasAlpha:NO
	isPlanar:NO
	colorSpace:NX_RGBColorSpace
	bytesPerRow:0
	bitsPerPixel:32];
    debug("Created Image %d %d %d\n", d->xsize, d->ysize, 24);
    debug("Data:"); for (i=0; i<20; i++) ndebug(" %x", ((unsigned int *)d->data)[i]);
    ndebug("\n");
    d->delta([bm data],d->data,d->fsize, act->chdr, act->chdr->map, 1, d->xsize,d->ysize,24,
					&xs,&ys,&xe,&ye,d->special,d->extra);
    debug("Delta area: %ld %ld %ld %ld\n", xs, ys, xe, ye);
    debug("Data:"); for (i=0; i<20; i++) ndebug(" %x", ((unsigned int *)[bm data])[i]);
    ndebug("\n");
    fd=open(stringf("pic%04d.tiff", cur_frame),O_WRONLY|O_CREAT,0644);
    s=NXOpenFile(fd,NX_WRITEONLY);
    debug("Opened pic%04d.tiff on channel %d: %x\n", cur_frame, fd, s);
    [bm writeTIFF:s];
    NXClose(s);
//    close(fd);
    debug("Written to pic%04d.tiff.\n", cur_frame);
}

void PrintAction()
{
    xa_debug=2;
    if ( (act = cur_file->frame_lst[cur_frame].act) != 0) {
	debug("Action %d, type %ld chdr %x map %x\n", cur_frame, 
	    act->type, act->chdr, act->chdr->map);
	if (act->type==ACT_DELTA) PrintDelta((ACT_DLTA_HDR *)act->data);
    } else error("No Action\n");
}


/***********************************************************************
 *
 *
 ***************/
void Hard_Death()
{
  XA_ANIM_HDR *tmp_hdr;
  if (xa_fd >= 0) { close(xa_fd); xa_fd = -1; }
  if (xa_codec_buf) { FREE(xa_codec_buf,0x99); xa_codec_buf=0;}
  if (cur_file !=0 )
  {
    cur_file = first_file;
    first_file->prev_file->next_file = 0;  /* last file's next ptr to 0 */
  }
  while( cur_file != 0)
  {
    Free_Actions(cur_file->acts);
    tmp_hdr = cur_file->next_file;
    if (cur_file->name) FREE(cur_file->name,0x01);
    FREE(cur_file,0x01);
    cur_file = tmp_hdr;
  }
  if (!shm)
  {
    if (im_buff0) { FREE(im_buff0,0x01); im_buff0=0; }
    if (im_buff1) { FREE(im_buff1,0x01); im_buff1=0; }
    if (im_buff2) { FREE(im_buff2,0x01); im_buff2=0; }
  }
  if (im_buff3) { FREE(im_buff3,0x01); im_buff3=0; }
  if (xa_disp_buff) { FREE(xa_disp_buff,0x01); xa_disp_buff=0; }
  if (xa_scale_buff) { FREE(xa_scale_buff,0x01); xa_scale_buff=0; }
  if (xa_scale_row_buff) { FREE(xa_scale_row_buff,0x01); xa_scale_row_buff=0;}
  if (xa_cmap) { FREE(xa_cmap,0x01); xa_cmap=0; }
  if (xa_ham_map) { FREE(xa_ham_map,0x001); xa_ham_map=0;}
  while(xa_chdr_start)
  {
    XA_CHDR *tmp;
    tmp = xa_chdr_start;
    xa_chdr_start = xa_chdr_start->next;
    if (tmp->cmap) { FREE(tmp->cmap,0x01); tmp->cmap=0; }
    if (tmp->map) { FREE(tmp->map,0x01); tmp->map=0; }
    FREE(tmp,0x01);
  }
#ifdef XSHM
  if (shm)
  {
    if (im0_shminfo.shmaddr) { XShmDetach(theDisp,&im0_shminfo);
		     shmdt(im0_shminfo.shmaddr); }
    if (im1_shminfo.shmaddr) { XShmDetach(theDisp,&im1_shminfo);
		     shmdt(im1_shminfo.shmaddr); }
    if (im2_shminfo.shmaddr) { XShmDetach(theDisp,&im2_shminfo);
		     shmdt(im2_shminfo.shmaddr); }
    if (im0_Image)
    {
      im0_Image->data = 0;
      XDestroyImage(im0_Image);
    }
    if (im1_Image)
    {
      im1_Image->data = 0;
      XDestroyImage(im1_Image);
    }
    if (im2_Image)
    {
      im2_Image->data = 0;
      XDestroyImage(im2_Image);
    }
  }
#endif
  exit(0);
}

NXImage *theImage;

/*
 * This function (hopefully) provides a clean exit from our code.
 */
void TheEnd()
{
  XA_ANIM_HDR *tmp_hdr;

  if (xa_fd>=0) { close(xa_fd); xa_fd = -1; }
  if (xa_codec_buf) { FREE(xa_codec_buf,0x99); xa_codec_buf=0;}
  if (cur_file !=0 )
  {
    cur_file = first_file;
    first_file->prev_file->next_file = 0;  /* last file's next ptr to 0 */
  }
  while( cur_file != 0)
  {
    Free_Actions(cur_file->acts);
    tmp_hdr = cur_file->next_file;
    if (cur_file->name) { FREE(cur_file->name,0x01); cur_file->name = 0; }
    FREE(cur_file,0x01);
    cur_file = tmp_hdr;
  }
  if (!shm)
  {
    if (im_buff0) { FREE(im_buff0,0x01); im_buff0=0; }
    if (im_buff1) { FREE(im_buff1,0x01); im_buff1=0; }
    if (im_buff2) { FREE(im_buff2,0x01); im_buff2=0; }
  }
  if (im_buff3) { FREE(im_buff3,0x01); im_buff3=0; }
  if (xa_disp_buff) { FREE(xa_disp_buff,0x01); xa_disp_buff=0; }
  if (xa_scale_buff) { FREE(xa_scale_buff,0x01); xa_scale_buff=0; }
  if (xa_scale_row_buff) { FREE(xa_scale_row_buff,0x01); xa_scale_row_buff=0;}
  if (xa_cmap) { FREE(xa_cmap,0x01); xa_cmap=0; }
  if (xa_ham_map) { FREE(xa_ham_map,0x001); xa_ham_map=0;}
#ifdef XSHM
  if (shm)
  {
    if (im0_shminfo.shmaddr) { XShmDetach(theDisp,&im0_shminfo);
		     shmdt(im0_shminfo.shmaddr); }
    if (im1_shminfo.shmaddr) { XShmDetach(theDisp,&im1_shminfo);
		     shmdt(im1_shminfo.shmaddr); }
    if (im2_shminfo.shmaddr) { XShmDetach(theDisp,&im2_shminfo);
		     shmdt(im2_shminfo.shmaddr); }
    if (im0_Image)
    {
      im0_Image->data = 0;
      XDestroyImage(im0_Image);
    }
    if (im1_Image)
    {
      im1_Image->data = 0;
      XDestroyImage(im1_Image);
    }
    if (im2_Image)
    {
      im2_Image->data = 0;
      XDestroyImage(im2_Image);
    }
  }
#endif
  if (theImage) [theImage free];
#if XJUNK
  if (theDisp) XtCloseDisplay(theDisp);
#endif
  while(xa_chdr_start)
  {
    XA_CHDR *tmp;
    tmp = xa_chdr_start;
    xa_chdr_start = xa_chdr_start->next;
    if (tmp->cmap) { FREE(tmp->cmap,0x01); tmp->cmap=0; }
    if (tmp->map) { FREE(tmp->map,0x01); tmp->map=0; }
    FREE(tmp,0x01);
  }
  exit(0);
}


/*
 * just prints a message before calling TheEnd()
 */
void TheEnd1(err_mess)
char *err_mess;
{
 fprintf(stderr,"%s\n",err_mess);
 TheEnd();
}


